├── .babelrc ├── .clang-format ├── .github └── workflows │ ├── deploywcc.yml │ └── test.yml ├── .gitignore ├── .gitpod.yml ├── LICENSE ├── Makefile ├── README.md ├── compile_flags.txt ├── eslint.config.mjs ├── examples ├── echo.c ├── fib.c ├── hello.c └── mandelbrot.c ├── include ├── alloca.h ├── ar.h ├── assert.h ├── ctype.h ├── elf.h ├── errno.h ├── fcntl.h ├── float.h ├── inttypes.h ├── libgen.h ├── limits.h ├── mach-o │ ├── arm64 │ │ └── reloc.h │ ├── loader.h │ ├── nlist.h │ ├── reloc.h │ └── x86_64 │ │ └── reloc.h ├── mach │ └── machine.h ├── math.h ├── setjmp.h ├── signal.h ├── stdarg.h ├── stdbool.h ├── stddef.h ├── stdint.h ├── stdio.h ├── stdlib.h ├── stdnoreturn.h ├── string.h ├── strings.h ├── sys │ ├── ioctl.h │ ├── random.h │ ├── stat.h │ ├── types.h │ └── wait.h ├── time.h ├── unistd.h └── wchar.h ├── libsrc ├── .gitignore ├── Makefile ├── _wasm │ ├── crt0 │ │ ├── __main_void.c │ │ ├── _start.c │ │ └── _start0.c │ ├── unistd │ │ ├── _detect_preopen.c │ │ ├── _set_stat.c │ │ ├── brk.c │ │ ├── clock_gettime.c │ │ ├── close.c │ │ ├── fstat.c │ │ ├── getcwd.c │ │ ├── lseek.c │ │ ├── lstat.c │ │ ├── mkdir.c │ │ ├── open.c │ │ ├── read.c │ │ ├── rmdir.c │ │ ├── stat.c │ │ ├── time.c │ │ ├── unlink.c │ │ └── write.c │ └── wasi.h ├── crt0 │ └── _start.c ├── math │ ├── _ieee.h │ ├── _normalize_radian.c │ ├── acos.c │ ├── acosh.c │ ├── asin.c │ ├── asinh.c │ ├── atan.c │ ├── atan2.c │ ├── atanh.c │ ├── ceil.c │ ├── copysign.c │ ├── cos.c │ ├── cosh.c │ ├── exp.c │ ├── fabs.c │ ├── fabsf.c │ ├── finite.c │ ├── floor.c │ ├── fmod.c │ ├── fpclassify.c │ ├── frexp.c │ ├── isinf.c │ ├── isnan.c │ ├── ldexp.c │ ├── log.c │ ├── log10.c │ ├── log2.c │ ├── modf.c │ ├── pow.c │ ├── round.c │ ├── signbit.c │ ├── sin.c │ ├── sinh.c │ ├── sqrt.c │ ├── tan.c │ └── tanh.c ├── misc │ ├── basename.c │ ├── dirname.c │ ├── errno.c │ ├── isalnum.c │ ├── isalpha.c │ ├── isascii.c │ ├── iscntrl.c │ ├── isdigit.c │ ├── isgraph.c │ ├── islower.c │ ├── isprint.c │ ├── ispunct.c │ ├── isspace.c │ ├── isupper.c │ ├── isxdigit.c │ ├── longjmp.c │ ├── setjmp.c │ ├── tolower.c │ └── toupper.c ├── stdio │ ├── _detect_open_flag.c │ ├── _file.c │ ├── _file.h │ ├── _fileman.c │ ├── _fileman.h │ ├── assert.c │ ├── fclose.c │ ├── fdopen.c │ ├── feof.c │ ├── fflush.c │ ├── fgetc.c │ ├── fgets.c │ ├── fileno.c │ ├── fmemopen.c │ ├── fopen.c │ ├── fprintf.c │ ├── fputc.c │ ├── fputs.c │ ├── fread.c │ ├── fseek.c │ ├── ftell.c │ ├── fwrite.c │ ├── getline.c │ ├── open_memstream.c │ ├── perror.c │ ├── printf.c │ ├── putchar.c │ ├── puts.c │ ├── remove.c │ ├── snprintf.c │ ├── sprintf.c │ ├── stdin.c │ ├── tmpfile.c │ ├── ungetc.c │ ├── vfprintf.c │ ├── vprintf.c │ ├── vsnprintf.c │ └── vsprintf.c ├── stdlib │ ├── __cxa_atexit.c │ ├── _exit.h │ ├── _malloc.h │ ├── _parse_sign.c │ ├── _strtoull_sub.c │ ├── abs.c │ ├── atexit.c │ ├── atof.c │ ├── atoi.c │ ├── atol.c │ ├── atoll.c │ ├── bsearch.c │ ├── calloc.c │ ├── drand48.c │ ├── environ.c │ ├── erand48.c │ ├── exit.c │ ├── getenv.c │ ├── getrandom.c │ ├── labs.c │ ├── llabs.c │ ├── lrand48.c │ ├── malloc.c │ ├── mkstemp.c │ ├── mkstemps.c │ ├── nrand48.c │ ├── qsort.c │ ├── rand.c │ ├── realloc.c │ ├── srand.c │ ├── strtod.c │ ├── strtol.c │ ├── strtold.c │ ├── strtoll.c │ ├── strtoul.c │ └── strtoull.c ├── string │ ├── memccpy.c │ ├── memchr.c │ ├── memcmp.c │ ├── memcpy.c │ ├── memmove.c │ ├── memset.c │ ├── stpcpy.c │ ├── stpncpy.c │ ├── strcasecmp.c │ ├── strcat.c │ ├── strchr.c │ ├── strcmp.c │ ├── strcoll.c │ ├── strcpy.c │ ├── strcspn.c │ ├── strdup.c │ ├── strerror.c │ ├── strerror_r.c │ ├── strlen.c │ ├── strncasecmp.c │ ├── strncat.c │ ├── strncmp.c │ ├── strncpy.c │ ├── strndup.c │ ├── strnlen.c │ ├── strpbrk.c │ ├── strrchr.c │ ├── strspn.c │ ├── strstr.c │ ├── strtok.c │ └── strtok_r.c ├── tests │ ├── file_test.c │ ├── longjmp_test.c │ ├── math_test.c │ ├── printf_test.c │ └── stdlib_test.c └── unistd │ ├── _syscall.h │ ├── brk.c │ ├── chdir.c │ ├── chmod.c │ ├── clock_gettime.c │ ├── clone3.c │ ├── close.c │ ├── dup.c │ ├── execve.c │ ├── execvp.c │ ├── fchmodat.c │ ├── fork.c │ ├── fstat.c │ ├── fstatat.c │ ├── getcwd.c │ ├── ioctl.c │ ├── isatty.c │ ├── kill.c │ ├── lseek.c │ ├── lstat.c │ ├── mkdir.c │ ├── mkdirat.c │ ├── open.c │ ├── openat.c │ ├── pipe.c │ ├── pipe2.c │ ├── read.c │ ├── rmdir.c │ ├── stat.c │ ├── time.c │ ├── unlink.c │ ├── unlinkat.c │ ├── wait.c │ ├── wait4.c │ ├── waitpid.c │ └── write.c ├── package-lock.json ├── package.json ├── src ├── _debug │ ├── dump_expr.c │ ├── dump_ir.c │ ├── dump_type.c │ └── wcc-ld.c ├── as │ ├── arch │ │ ├── aarch64 │ │ │ ├── aarch64_code.h │ │ │ ├── asm_code.c │ │ │ ├── inst.h │ │ │ ├── ir_asm_aarch64.c │ │ │ └── parse_aarch64.c │ │ ├── riscv64 │ │ │ ├── asm_code.c │ │ │ ├── inst.h │ │ │ ├── ir_asm_riscv64.c │ │ │ ├── parse_riscv64.c │ │ │ └── riscv64_code.h │ │ └── x64 │ │ │ ├── asm_code.c │ │ │ ├── inst.h │ │ │ ├── ir_asm_x64.c │ │ │ └── parse_x64.c │ ├── as.c │ ├── as_util.c │ ├── as_util.h │ ├── asm_code.h │ ├── emit_elf.c │ ├── emit_macho.c │ ├── ir_asm.c │ ├── ir_asm.h │ ├── parse_asm.c │ └── parse_asm.h ├── cc │ ├── arch │ │ ├── aarch64 │ │ │ ├── aarch64.h │ │ │ ├── arch_config.h │ │ │ ├── emit_aarch64.c │ │ │ └── ir_aarch64.c │ │ ├── riscv64 │ │ │ ├── arch_config.h │ │ │ ├── emit_riscv64.c │ │ │ ├── ir_riscv64.c │ │ │ └── riscv64.h │ │ └── x64 │ │ │ ├── arch_config.h │ │ │ ├── emit_x64.c │ │ │ ├── ir_x64.c │ │ │ └── x64.h │ ├── backend │ │ ├── codegen.c │ │ ├── codegen.h │ │ ├── codegen_expr.c │ │ ├── emit_code.c │ │ ├── emit_code.h │ │ ├── ir.c │ │ ├── ir.h │ │ ├── optimize.c │ │ ├── optimize.h │ │ ├── regalloc.c │ │ ├── regalloc.h │ │ ├── ssa.c │ │ └── ssa.h │ ├── builtin.c │ ├── cc1.c │ └── frontend │ │ ├── ast.c │ │ ├── ast.h │ │ ├── cc_misc.c │ │ ├── cc_misc.h │ │ ├── fe_misc.c │ │ ├── fe_misc.h │ │ ├── initializer.c │ │ ├── initializer.h │ │ ├── lexer.c │ │ ├── lexer.h │ │ ├── parser.c │ │ ├── parser.h │ │ ├── parser_expr.c │ │ ├── parser_type.c │ │ ├── type.c │ │ ├── type.h │ │ ├── var.c │ │ └── var.h ├── config.h ├── cpp │ ├── cpp.c │ ├── macro.c │ ├── macro.h │ ├── pp_parser.c │ ├── pp_parser.h │ ├── preprocessor.c │ └── preprocessor.h ├── ld │ ├── elfobj.c │ ├── elfobj.h │ └── ld.c ├── util │ ├── archive.c │ ├── archive.h │ ├── elfutil.c │ ├── elfutil.h │ ├── table.c │ ├── table.h │ ├── util.c │ └── util.h ├── version.h ├── wcc │ ├── emit_wasm.c │ ├── gen_wasm.c │ ├── traverse.c │ ├── traverse_setjmp.c │ ├── wasm.h │ ├── wasm_linker.c │ ├── wasm_linker.h │ ├── wasm_obj.h │ ├── wcc.c │ ├── wcc.h │ ├── wcc_util.c │ └── www │ │ ├── @types │ │ ├── c.d.ts │ │ └── patch.d.ts │ │ ├── default.scss │ │ ├── diswasm.ts │ │ ├── examples │ │ ├── aobench.c │ │ ├── hello.c │ │ ├── qsort.c │ │ └── sieve.c │ │ ├── index.html │ │ ├── lib_list.json │ │ ├── main.ts │ │ ├── util.ts │ │ ├── wa_proc.ts │ │ ├── wasi_worker.ts │ │ └── wcc_runner.ts └── xcc │ └── main.c ├── tests ├── Makefile ├── cpptest.sh ├── example_test.sh ├── flotest.inc ├── fvaltest.c ├── initializer_test.c ├── link_main.c ├── link_sub.c ├── mandel256.ppm ├── parser_test.c ├── print_type_test.c ├── table_test.c ├── test.sh ├── test_sub.sh ├── thirdparty │ ├── cpython.sh │ ├── git.sh │ ├── libpng.sh │ ├── lua.sh │ ├── sqlite.sh │ ├── thirdpartycommon │ └── tinycc.sh ├── util_test.c ├── valtest.c └── xtest.h ├── tool ├── diswasm.ts ├── find-riscv-toolchain ├── pack_libs.js ├── pp.js ├── run-gen2wcc.sh ├── run-riscv64 ├── runwasi ├── runwasi.js └── xccsh ├── tsconfig.json ├── vite.config.mts └── wcc.png /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "useBuiltIns": "usage", 7 | "corejs": 3 8 | } 9 | ] 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AllowShortCaseLabelsOnASingleLine: true 4 | AllowShortFunctionsOnASingleLine: None 5 | AllowShortIfStatementsOnASingleLine: Never 6 | AllowShortLoopsOnASingleLine: false 7 | BreakBeforeBraces: Custom 8 | BraceWrapping: 9 | AfterCaseLabel: true 10 | ColumnLimit: 100 11 | IndentCaseLabels: false 12 | IndentCaseBlocks: true 13 | -------------------------------------------------------------------------------- /.github/workflows/deploywcc.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy gh-pages 2 | 3 | on: 4 | workflow_run: 5 | workflows: [AllTests] 6 | types: [completed] 7 | branches: 8 | - main 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: 20.x 20 | - name: Setup llvm-ar 21 | run: sudo apt install llvm-dev 22 | - name: Install NPM packages 23 | run: npm ci 24 | - name: Build release 25 | run: make release-wcc 26 | - name: Upload artifact 27 | uses: actions/upload-pages-artifact@v3 28 | with: 29 | path: release 30 | 31 | deploy: 32 | runs-on: ubuntu-latest 33 | needs: build 34 | permissions: 35 | pages: write 36 | id-token: write 37 | environment: 38 | name: github-pages 39 | url: ${{ steps.deployment.outputs.page_url }} 40 | steps: 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v4 44 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: AllTests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | - actions/** 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 20.x 22 | 23 | - name: make xcc 24 | run: make -j8 all 25 | - name: test xcc 26 | run: make test 27 | - name: test xcc gen2 28 | run: make test-gen2 29 | 30 | - name: test ssa 31 | run: make test-ssa 32 | 33 | - name: setup 34 | run: | 35 | npm ci 36 | sudo apt update && sudo apt install llvm-dev 37 | - name: make wcc 38 | run: make -j8 wcc 39 | - name: test wcc 40 | run: make test-wcc 41 | - name: test wcc gen2 42 | run: make test-wcc-gen2 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.a 3 | *.d 4 | *.o 5 | a.out 6 | tmp* 7 | core 8 | ,* 9 | .#* 10 | .vscode 11 | /as 12 | /cc1 13 | /cpp 14 | /gen2* 15 | /gen3* 16 | /ld 17 | /xcc 18 | /obj 19 | /lib 20 | /tests/core.* 21 | /tests/dvaltest 22 | /tests/fvaltest 23 | /tests/initializer_test 24 | /tests/link_test 25 | /tests/mandelbrot.ppm 26 | /tests/parser_test 27 | /tests/print_type_test 28 | /tests/table_test 29 | /tests/util_test 30 | /tests/valtest 31 | /dump_expr* 32 | /dump_ir* 33 | /dump_type* 34 | 35 | /tests/thirdparty/.external/ 36 | 37 | ### wasm 38 | 39 | *.wasm 40 | /wcc 41 | /wcc-ld 42 | /cc.wasm 43 | /gen3cc.wasm 44 | /tests/*.wasm 45 | 46 | /public/ 47 | /release/ 48 | node_modules 49 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - command: > 3 | ulimit -c 0; 4 | git config --local alias.alias "config --get-regexp 'alias.*'"; 5 | git config --local alias.br branch; 6 | git config --local alias.cp cherry-pick; 7 | git config --local alias.rco '!'"sh -c 'if [ -z \"\$2\" ]; then git branch \$1 origin/\$1; git switch \$1; else git branch \$1 \$2/\$1; git switch \$2; fi;' -"; 8 | git config --local alias.rtm "rebase main"; 9 | git config --local alias.s status; 10 | git config --local alias.sp "stash pop"; 11 | git config --local alias.ss "stash save"; 12 | git config --local alias.sw switch; 13 | git config --local alias.tree "log --graph --branches --date=short --format=\"%C(yellow)%h %C(magenta)%ad%C(auto)%d%C(reset) %C(bold)%s%C(reset) %C(cyan)%an\""; 14 | git config --local alias.fix '!'"sh -c 'git commit --fixup \$1 && git rebase -i --autosquash \$1~1 --autostash' -"; 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 tyfkda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -I./src/as 2 | -I./src/cc/backend 3 | -I./src/cc/frontend 4 | -I./src/cpp 5 | -I./src/util 6 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js' 2 | // import tseslint from 'typescript-eslint' 3 | 4 | export default [ 5 | eslint.configs.recommended, 6 | // ...tseslint.configs.recommended, 7 | { 8 | // extends: [ 9 | // 'eslint:recommended', 10 | // 'plugin:@typescript-eslint/eslint-recommended', 11 | // 'plugin:@typescript-eslint/recommended', 12 | // ], 13 | plugins: [ 14 | '@typescript-eslint', 15 | ], 16 | env: { node: true, es6: true }, 17 | parser: '@typescript-eslint/parser', 18 | parserOptions: { 19 | sourceType: 'module', 20 | project: './tsconfig.json', 21 | }, 22 | rules: { 23 | 'nonblock-statement-body-position': ['error', 'below'], 24 | 'quotes': ['error', 'single', { "avoidEscape": true }], 25 | 'semi': ['error', 'never'], 26 | 27 | '@typescript-eslint/no-unused-vars': ['error', { 'varsIgnorePattern': '^_', 'argsIgnorePattern': '^_' }], 28 | '@typescript-eslint/no-explicit-any': 'off', 29 | '@typescript-eslint/no-non-null-assertion': 'off', 30 | }, 31 | }, 32 | ] 33 | -------------------------------------------------------------------------------- /examples/echo.c: -------------------------------------------------------------------------------- 1 | // Echo : Handle command line arguments 2 | // 3 | // Compile: 4 | // $ ./xcc -oecho examples/echo.c 5 | // 6 | // Run: 7 | // $ ./echo foo bar baz #=> foo bar baz 8 | 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | for (int i = 1; i < argc; ++i) { 13 | if (i > 1) 14 | printf(" "); 15 | printf("%s", argv[i]); 16 | } 17 | printf("\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/fib.c: -------------------------------------------------------------------------------- 1 | // Fib : Calculate fibonacci (30) 2 | // 3 | // Compile: 4 | // $ ./xcc -ofib examples/fib.c 5 | // 6 | // Run: 7 | // $ ./fib #=> 832040 8 | 9 | #include 10 | 11 | int fib(int n) { 12 | if (n < 2) 13 | return n; 14 | else 15 | return fib(n - 1) + fib(n - 2); 16 | } 17 | 18 | int main() { 19 | printf("%d\n", fib(30)); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/hello.c: -------------------------------------------------------------------------------- 1 | // Hello world! 2 | // 3 | // Compile: 4 | // $ ./xcc -ohello examples/hello.c 5 | // 6 | // Run: 7 | // $ ./hello #=> Hello, world! 8 | 9 | #include 10 | 11 | int main() { 12 | printf("Hello, world!\n"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/mandelbrot.c: -------------------------------------------------------------------------------- 1 | // Mandelbrot 2 | 3 | // Compile: 4 | // $ ./xcc -omandelbrot examples/mandelbrot.c 5 | // Run: 6 | // $ time ./mandelbrot #=> mandelbrot.ppm is generated. 7 | 8 | #include 9 | #include 10 | 11 | #ifdef USE_SINGLE 12 | typedef float Number; 13 | #else 14 | typedef double Number; 15 | #endif 16 | 17 | #ifdef NO_USE_MORE_FPREG 18 | #define Integer int 19 | #else 20 | #define Integer Number 21 | #endif 22 | 23 | // 0..finite, >0..divergence count. 24 | Integer mandelbrot(Number cx, Number cy, Integer threshold) { 25 | Number x = 0, y = 0; 26 | for (Integer n = 1; n <= threshold; ++n) { 27 | if (x * x + y * y > 4) 28 | return n; 29 | Number nx = x * x - y * y + cx; 30 | Number ny = 2 * x * y + cy; 31 | x = nx; 32 | y = ny; 33 | } 34 | return 0; 35 | } 36 | 37 | unsigned int calc_color(unsigned int n) { 38 | unsigned char r = n * 3; 39 | unsigned char g = n * 2; 40 | unsigned char b = n * 11; 41 | return (((unsigned int)r) << 16) | (((unsigned int)g) << 8) | b; 42 | } 43 | 44 | int main(int argc, char *argv[]) { 45 | Integer threshold = argc > 1 ? atoi(argv[1]) : 3000; 46 | Integer W = argc > 2 ? atoi(argv[2]) : 512; 47 | Integer H = argc > 3 ? atoi(argv[3]) : 512; 48 | 49 | const Number XMIN = -1.75; 50 | const Number YMIN = -1.125; 51 | Number XS = 2.25, YS = XS * H / W; 52 | 53 | unsigned char *buf = malloc(W * H * 3); 54 | if (buf == NULL) { 55 | fprintf(stderr, "out of memory\n"); 56 | exit(1); 57 | } 58 | unsigned char *p = buf; 59 | 60 | for (Integer i = 0; i < H; ++i) { 61 | Number cy = YS * i / H + YMIN; 62 | for (Integer j = 0; j < W; ++j) { 63 | Number cx = XS * j / W + XMIN; 64 | Integer n = mandelbrot(cx, cy, threshold); 65 | unsigned int c = calc_color(n); 66 | *p++ = c >> 16; 67 | *p++ = c >> 8; 68 | *p++ = c; 69 | } 70 | } 71 | 72 | FILE *fp = fopen("mandelbrot.ppm", "wb"); 73 | if (fp == NULL) { 74 | exit(1); 75 | } 76 | fprintf(fp, "P6\n%d %d\n255\n", (int)W, (int)H); 77 | fwrite(buf, W * H * 3, 1, fp); 78 | fclose(fp); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /include/alloca.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__GNUC__) && !defined(__XCC) 4 | 5 | #include_next 6 | 7 | #else 8 | 9 | #include // size_t 10 | 11 | void *alloca(size_t size); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/ar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ARMAG "!\n" 4 | #define SARMAG (8) 5 | 6 | #define ARFMAG "`\n" 7 | 8 | struct ar_hdr { 9 | char ar_name[16]; 10 | char ar_date[12]; 11 | char ar_uid[6], ar_gid[6]; 12 | char ar_mode[8]; 13 | char ar_size[10]; 14 | char ar_fmag[2]; 15 | }; 16 | -------------------------------------------------------------------------------- /include/assert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(NDEBUG) 4 | #define assert(x) ((void)0) 5 | 6 | #elif defined(__APPLE__) 7 | 8 | void __assert_rtn(const char *, const char *, int, const char *); // __dead2 __cold __disable_tail_calls; 9 | #define assert(x) ((x) ? ((void)0) : __assert_rtn(__FUNCTION__, __FILE__, __LINE__, #x)) 10 | 11 | #else 12 | 13 | extern void __assert_fail(const char *assertion, const char *fn, int lineno, const char *func); 14 | #define assert(x) ((x) ? ((void)0) : __assert_fail(#x, __FILE__, __LINE__, __FUNCTION__)) 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/ctype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int isdigit(int c); 4 | int isxdigit(int c); 5 | int isalpha(int c); 6 | int isalnum(int c); 7 | int isspace(int c); 8 | int isupper(int c); 9 | int islower(int c); 10 | int isascii(int c); 11 | int isprint(int c); 12 | int isgraph(int c); 13 | int iscntrl(int c); 14 | int ispunct(int c); 15 | 16 | int tolower(int c); 17 | int toupper(int c); 18 | -------------------------------------------------------------------------------- /include/errno.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__riscv) 4 | extern int errno; 5 | 6 | #elif defined(__APPLE__) 7 | extern int * __error(void); 8 | #define errno (*__error()) 9 | 10 | #else 11 | extern int *__errno_location(void) /*__THROW __attribute__((__const__))*/; 12 | #define errno (*__errno_location()) 13 | #endif 14 | 15 | #define EPERM 1 /* Operation not permitted */ 16 | #define ENOENT 2 /* No such file or directory */ 17 | #define ESRCH 3 /* No such process */ 18 | #define EINTR 4 /* Interrupted system call */ 19 | #define EIO 5 /* I/O error */ 20 | #define ENXIO 6 /* No such device or address */ 21 | #define E2BIG 7 /* Argument list too long */ 22 | #define ENOEXEC 8 /* Exec format error */ 23 | #define EBADF 9 /* Bad file number */ 24 | #define ECHILD 10 /* No child processes */ 25 | #define EAGAIN 11 /* Try again */ 26 | #define ENOMEM 12 /* Out of memory */ 27 | #define EACCES 13 /* Permission denied */ 28 | #define EFAULT 14 /* Bad address */ 29 | #define ENOTBLK 15 /* Block device required */ 30 | #define EBUSY 16 /* Device or resource busy */ 31 | #define EEXIST 17 /* File exists */ 32 | #define EXDEV 18 /* Cross-device link */ 33 | #define ENODEV 19 /* No such device */ 34 | #define ENOTDIR 20 /* Not a directory */ 35 | #define EISDIR 21 /* Is a directory */ 36 | #define EINVAL 22 /* Invalid argument */ 37 | #define ENFILE 23 /* File table overflow */ 38 | #define EMFILE 24 /* Too many open files */ 39 | #define ENOTTY 25 /* Not a typewriter */ 40 | #define ETXTBSY 26 /* Text file busy */ 41 | #define EFBIG 27 /* File too large */ 42 | #define ENOSPC 28 /* No space left on device */ 43 | #define ESPIPE 29 /* Illegal seek */ 44 | #define EROFS 30 /* Read-only file system */ 45 | #define EMLINK 31 /* Too many links */ 46 | #define EPIPE 32 /* Broken pipe */ 47 | #define EDOM 33 /* Math argument out of domain of func */ 48 | #define ERANGE 34 /* Math result not representable */ 49 | -------------------------------------------------------------------------------- /include/fcntl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define O_RDONLY (00) 4 | #define O_WRONLY (01) 5 | #define O_RDWR (02) 6 | #define O_ACCMODE (03) 7 | #define O_CREAT (0100) 8 | #define O_EXCL (0200) 9 | #define O_TRUNC (01000) 10 | #define O_APPEND (02000) 11 | 12 | #define S_IRUSR (0400) 13 | #define S_IWUSR (0200) 14 | #define S_IXUSR (0100) 15 | #define S_IRGRP (0040) 16 | #define S_IWGRP (0020) 17 | #define S_IXGRP (0010) 18 | #define S_IROTH (0004) 19 | #define S_IWOTH (0002) 20 | #define S_IXOTH (0001) 21 | 22 | #ifdef __APPLE__ 23 | #define AT_FDCWD -2 24 | #else 25 | #define AT_FDCWD -100 26 | #endif 27 | 28 | #define AT_SYMLINK_NOFOLLOW 0x100 29 | #define AT_SYMLINK_FOLLOW 0x400 30 | 31 | /* Flag for faccessat(2). */ 32 | #define AT_EACCESS 0x200 33 | 34 | /* Flag for unlinkat(2). */ 35 | #if defined(__AT_REMOVEDIR) 36 | #define AT_REMOVEDIR __AT_REMOVEDIR 37 | #elif defined(__APPLE__) 38 | #define AT_REMOVEDIR 0x080 39 | #else 40 | #define AT_REMOVEDIR 0x200 41 | #endif 42 | 43 | int open(const char *fn, int flag, ...); 44 | int openat(int dirfd, const char *fn, int flag, ...); 45 | -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define FLT_RADIX (2) 4 | 5 | #define DBL_MANT_DIG (53) 6 | #define DBL_DIG (15) 7 | #define DBL_MIN_EXP (-1021) 8 | #define DBL_MAX_EXP (1024) 9 | #define DBL_MIN_10_EXP (-307) 10 | #define DBL_MAX_10_EXP (308) 11 | #define DBL_MIN (2.2250738585072014e-308) 12 | #define DBL_MAX (1.7976931348623158e+308) 13 | #define DBL_EPSILON (2.220446049250313e-16) 14 | 15 | #define FLT_MANT_DIG (24) 16 | #define FLT_DIG (6) 17 | #define FLT_MIN_EXP (-125) 18 | #define FLT_MAX_EXP (128) 19 | #define FLT_MIN_10_EXP (-37) 20 | #define FLT_MAX_10_EXP (38) 21 | #define FLT_MIN (1.1754943508222875e-38) 22 | #define FLT_MAX (3.402823669209385e+38) 23 | #define FLT_EPSILON (1.1920928955078125e-07) 24 | 25 | #define FLT_ROUNDS (1) // TODO 26 | -------------------------------------------------------------------------------- /include/inttypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PRId32 "ld" 4 | #define PRIu32 "lu" 5 | #define PRIx32 "lx" 6 | #define PRIdPTR "ld" 7 | #define PRIxPTR "lx" 8 | 9 | #if defined(__ILP32__) 10 | 11 | #define PRId64 "lld" 12 | #define PRIu64 "llu" 13 | #define PRIx64 "llx" 14 | 15 | #elif defined(__LP64__) 16 | 17 | #define PRId64 "ld" 18 | #define PRIu64 "lu" 19 | #define PRIx64 "lx" 20 | 21 | #else 22 | // ? 23 | #endif 24 | 25 | #define PRIdMAX "lld" 26 | #define PRIuMAX "llu" 27 | #define PRIoMAX "llo" 28 | -------------------------------------------------------------------------------- /include/libgen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char *dirname(char *); 4 | char *basename(char *); 5 | -------------------------------------------------------------------------------- /include/limits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CHAR_BIT (8) // Number of bits in one char 4 | 5 | #define CHAR_MIN (-128) // -(2^7) 6 | #define CHAR_MAX (127) // (2^7)-1 7 | #define UCHAR_MAX (255) // (2^8)-1 8 | 9 | #define SHRT_MIN (-32768) // -(2^15) 10 | #define SHRT_MAX ( 32767) // (2^15)-1 11 | #define USHRT_MAX (65535) // (2^16)-1 12 | 13 | #define INT_MIN (-2147483648) // -(2^31) 14 | #define INT_MAX ( 2147483647) // (2^31)-1 15 | #define UINT_MAX (4294967295) // (2^32)-1 16 | 17 | #if defined(__ILP32__) 18 | 19 | #define LONG_MIN (-2147483648) // -(2^31) 20 | #define LONG_MAX ( 2147483647) // (2^31)-1 21 | #define ULONG_MAX (4294967295) // (2^32)-1 22 | 23 | #define LLONG_MIN (-9223372036854775808LL) // -(2^63) 24 | #define LLONG_MAX ( 9223372036854775807LL) // (2^63)-1 25 | #define ULLONG_MAX (18446744073709551615ULL) // (2^64)-1 26 | 27 | #elif defined(__LP64__) 28 | 29 | #define LONG_MIN (-9223372036854775808L) // -(2^63) 30 | #define LONG_MAX ( 9223372036854775807L) // (2^63)-1 31 | #define ULONG_MAX (18446744073709551615UL) // (2^64)-1 32 | 33 | #define LLONG_MIN (-9223372036854775808LL) // -(2^63) 34 | #define LLONG_MAX ( 9223372036854775807LL) // (2^63)-1 35 | #define ULLONG_MAX (18446744073709551615ULL) // (2^64)-1 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/mach-o/arm64/reloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // MachoArm64RelocationType 4 | #define ARM64_RELOC_UNSIGNED 0 5 | #define ARM64_RELOC_BRANCH26 2 6 | #define ARM64_RELOC_PAGE21 3 7 | #define ARM64_RELOC_PAGEOFF12 4 8 | #define ARM64_RELOC_GOT_LOAD_PAGE21 5 9 | #define ARM64_RELOC_GOT_LOAD_PAGEOFF12 6 10 | #define ARM64_RELOC_ADDEND 10 11 | -------------------------------------------------------------------------------- /include/mach-o/loader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct mach_header_64 { 6 | uint32_t magic; 7 | int32_t cputype; 8 | int32_t cpusubtype; 9 | uint32_t filetype; 10 | uint32_t ncmds; 11 | uint32_t sizeofcmds; 12 | uint32_t flags; 13 | uint32_t reserved; 14 | }; 15 | 16 | #define MH_MAGIC_64 0xfeedfacf 17 | 18 | #define MH_OBJECT 0x1 19 | #define MH_EXECUTE 0x2 20 | 21 | #define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000 22 | 23 | struct load_command { 24 | uint32_t cmd; 25 | uint32_t cmdsize; 26 | }; 27 | 28 | #define LC_SYMTAB 0x2 29 | #define LC_SEGMENT_64 0x19 30 | #define LC_BUILD_VERSION 0x32 31 | 32 | struct symtab_command { 33 | uint32_t cmd; 34 | uint32_t cmdsize; 35 | uint32_t symoff; 36 | uint32_t nsyms; 37 | uint32_t stroff; 38 | uint32_t strsize; 39 | }; 40 | 41 | struct segment_command_64 { /* for 64-bit architectures */ 42 | uint32_t cmd; 43 | uint32_t cmdsize; 44 | char segname[16]; 45 | uint64_t vmaddr; 46 | uint64_t vmsize; 47 | uint64_t fileoff; 48 | uint64_t filesize; 49 | int32_t maxprot; 50 | int32_t initprot; 51 | uint32_t nsects; 52 | uint32_t flags; 53 | }; 54 | 55 | struct build_version_command { 56 | uint32_t cmd; 57 | uint32_t cmdsize; 58 | uint32_t platform; 59 | uint32_t minos; 60 | uint32_t sdk; 61 | uint32_t ntools; 62 | }; 63 | 64 | #define PLATFORM_MACOS 1 65 | 66 | struct section_64 { /* for 64-bit architectures */ 67 | char sectname[16]; 68 | char segname[16]; 69 | uint64_t addr; 70 | uint64_t size; 71 | uint32_t offset; 72 | uint32_t align; 73 | uint32_t reloff; 74 | uint32_t nreloc; 75 | uint32_t flags; 76 | uint32_t reserved1; 77 | uint32_t reserved2; 78 | uint32_t reserved3; 79 | }; 80 | 81 | #define S_REGULAR 0x0 82 | #define S_ZEROFILL 0x1 83 | #define S_CSTRING_LITERALS 0x2 84 | #define S_MOD_INIT_FUNC_POINTERS 0x9 85 | 86 | #define S_ATTR_PURE_INSTRUCTIONS 0x80000000 87 | #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 88 | -------------------------------------------------------------------------------- /include/mach-o/nlist.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define N_STAB 0xe0 6 | #define N_PEXT 0x10 7 | #define N_TYPE 0x0e 8 | #define N_EXT 0x01 9 | 10 | #define N_UNDF 0x0 11 | #define N_ABS 0x2 12 | #define N_SECT 0xe 13 | #define N_PBUD 0xc 14 | #define N_INDR 0xa 15 | 16 | #define N_WEAK_DEF 0x0080 17 | 18 | struct nlist_64 { 19 | union { 20 | uint32_t n_strx; 21 | } n_un; 22 | uint8_t n_type; 23 | uint8_t n_sect; 24 | uint16_t n_desc; 25 | uint64_t n_value; 26 | }; 27 | 28 | #define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f) 29 | #define SET_COMM_ALIGN(n_desc, align) (n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8)) 30 | -------------------------------------------------------------------------------- /include/mach-o/reloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct relocation_info { 6 | int32_t r_address; 7 | #ifndef __NO_BITFIELD 8 | uint32_t 9 | r_symbolnum : 24, 10 | r_pcrel : 1, 11 | r_length : 2, 12 | r_extern : 1, 13 | r_type : 4; 14 | #else 15 | uint32_t r_pack; 16 | #endif 17 | }; 18 | #define R_ABS 0 19 | -------------------------------------------------------------------------------- /include/mach-o/x86_64/reloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum reloc_type_x86_64 { 4 | X86_64_RELOC_UNSIGNED, 5 | X86_64_RELOC_SIGNED, 6 | X86_64_RELOC_BRANCH, 7 | X86_64_RELOC_GOT_LOAD, 8 | X86_64_RELOC_GOT, 9 | X86_64_RELOC_SUBTRACTOR, 10 | X86_64_RELOC_SIGNED_1, 11 | X86_64_RELOC_SIGNED_2, 12 | X86_64_RELOC_SIGNED_4, 13 | }; 14 | -------------------------------------------------------------------------------- /include/mach/machine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CPU_TYPE_ARM ((cpu_type_t)12) 4 | #define CPU_TYPE_X86 ((cpu_type_t)7) 5 | 6 | #define CPU_ARCH_MASK 0xff000000 7 | #define CPU_ARCH_ABI64 0x01000000 8 | 9 | #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) 10 | 11 | #define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) 12 | 13 | #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) 14 | 15 | #define CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t)0) 16 | 17 | typedef int integer_t; 18 | typedef integer_t cpu_type_t; 19 | typedef integer_t cpu_subtype_t; 20 | -------------------------------------------------------------------------------- /include/setjmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uintptr_t 4 | 5 | #if defined(__WASM) 6 | typedef uintptr_t jmp_buf[2]; // 0=Stack pointer, 1=longjmp-result. 7 | 8 | #elif defined(__aarch64__) 9 | typedef uintptr_t jmp_buf[192 / 8]; 10 | 11 | #elif defined(__x86_64__) 12 | typedef uintptr_t jmp_buf[200 / 8]; // GCC 13 | 14 | #elif defined(__riscv) 15 | typedef uintptr_t jmp_buf[208 / 8]; 16 | #endif 17 | 18 | int setjmp(jmp_buf env); 19 | _Noreturn void longjmp(jmp_buf env, int result); 20 | 21 | #define _setjmp setjmp 22 | #define _longjmp longjmp 23 | 24 | #ifdef __WASM 25 | #define setjmp(env) __builtin_setjmp(env) 26 | #define longjmp(env, result) __builtin_longjmp(env, result) 27 | #endif 28 | -------------------------------------------------------------------------------- /include/signal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // pid_t 4 | 5 | #define SIGKILL 9 6 | #define SIGCHLD 17 7 | 8 | #define SIG_DFL ((void (*)(int))0) 9 | 10 | int kill(pid_t pid, int sig); 11 | 12 | void (*signal(int sig, void (*func)(int)))(int); 13 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define bool _Bool 4 | #define false (0) 5 | #define true (1) 6 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NULL 4 | #define NULL ((void*)0) 5 | #endif 6 | 7 | #define offsetof(S, mem) ((size_t)&(((S *)0)->mem)) 8 | 9 | typedef unsigned long size_t; 10 | typedef long ptrdiff_t; 11 | 12 | // 13 | 14 | #ifndef _WCHAR_T_DEFINED 15 | #define _WCHAR_T_DEFINED 16 | typedef unsigned int wchar_t; 17 | #endif 18 | -------------------------------------------------------------------------------- /include/stdint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef char int8_t; 6 | typedef unsigned char uint8_t; 7 | 8 | typedef short int16_t; 9 | typedef unsigned short uint16_t; 10 | 11 | typedef int int32_t; 12 | typedef unsigned int uint32_t; 13 | 14 | typedef long long int64_t; 15 | typedef unsigned long long uint64_t; 16 | 17 | #if defined(__ILP32__) 18 | #define INTPTR_MAX INT32_MIN 19 | #define INTPTR_MIN INT32_MAX 20 | 21 | #else 22 | 23 | #define INTPTR_MAX INT64_MIN 24 | #define INTPTR_MIN INT64_MAX 25 | #endif 26 | 27 | typedef long intptr_t; 28 | typedef unsigned long uintptr_t; 29 | 30 | typedef long long intmax_t; 31 | typedef unsigned long long uintmax_t; 32 | 33 | #define INT8_MIN -128 34 | #define INT8_MAX 127 35 | #define UINT8_MAX 255 36 | 37 | #define INT16_MIN -32768 38 | #define INT16_MAX 32767 39 | #define UINT16_MAX 65535 40 | 41 | #define INT32_MIN -2147483648 42 | #define INT32_MAX 2147483647 43 | #define UINT32_MAX 4294967295 44 | 45 | #define INT64_MIN -9223372036854775808 46 | #define INT64_MAX 9223372036854775807 47 | #define UINT64_MAX 18446744073709551615 48 | 49 | #define INTMAX_MIN INT64_MIN 50 | #define INTMAX_MAX INT64_MAX 51 | #define UINTMAX_MAX UINT64_MAX 52 | -------------------------------------------------------------------------------- /include/stdio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include // ssize_t 6 | 7 | #define EOF (-1) 8 | 9 | enum { 10 | SEEK_SET, // 0 11 | SEEK_CUR, // 1 12 | SEEK_END, // 2 13 | }; 14 | 15 | typedef struct FILE FILE; 16 | 17 | #ifdef __APPLE__ 18 | extern FILE *__stdinp; 19 | extern FILE *__stdoutp; 20 | extern FILE *__stderrp; 21 | #define stdin __stdinp 22 | #define stdout __stdoutp 23 | #define stderr __stderrp 24 | 25 | #elif defined(__riscv) 26 | 27 | // Must match with newlib 28 | struct _reent 29 | { 30 | int _errno; 31 | 32 | struct FILE *_stdin, *_stdout, *_stderr; 33 | }; 34 | 35 | extern struct _reent *_impure_ptr; 36 | 37 | #define stdin (_impure_ptr->_stdin) 38 | #define stdout (_impure_ptr->_stdout) 39 | #define stderr (_impure_ptr->_stderr) 40 | 41 | #else 42 | extern FILE *stdin; 43 | extern FILE *stdout; 44 | extern FILE *stderr; 45 | #endif 46 | 47 | FILE *fopen(const char *fileName, const char *mode); 48 | FILE *fdopen(int fd, const char *mode); 49 | int fclose(FILE *fp); 50 | size_t fwrite(const void *buffer, size_t size, size_t count, FILE *fp); 51 | size_t fread(void *buffer, size_t size, size_t count, FILE *fp); 52 | int fflush(FILE *fp); 53 | int fseek(FILE *fp, long offset, int origin); 54 | long ftell(FILE *fp); 55 | int feof(FILE *fp); 56 | int remove(const char *fn); 57 | 58 | int fgetc(FILE *fp); 59 | int fputc(int c, FILE *fp); 60 | char *fgets(char *s, int n, FILE *fp); 61 | int fputs(const char *s, FILE *fp); 62 | int puts(const char *s); 63 | int ungetc(int c, FILE *fp); 64 | 65 | #define getc(fp) fgetc(fp) 66 | #define getchar() fgetc(stdin) 67 | #define putc(c, fp) fputc(c, fp) 68 | #define putchar(c) fputc(c, stdout) 69 | 70 | int fprintf(FILE *fp, const char *fmt, ...); 71 | int printf(const char *fmt, ...); 72 | int sprintf(char *out, const char *fmt, ...); 73 | int snprintf(char *, size_t n, const char *, ...); 74 | int vprintf(const char *fmt, va_list ap); 75 | int vsprintf(char *buf, const char *fmt, va_list ap); 76 | int vfprintf(FILE *fp, const char *fmt, va_list ap); 77 | int vsnprintf(char *out, size_t n, const char *fmt_, va_list ap); 78 | 79 | void perror(const char *); 80 | 81 | int fileno(FILE *fp); 82 | FILE *tmpfile(void); 83 | 84 | ssize_t getline(char **lineptr, size_t *n, FILE *stream); 85 | 86 | FILE *fmemopen(void *buf, size_t size, const char *mode); 87 | FILE *open_memstream(char **ptr, size_t *sizeloc); 88 | -------------------------------------------------------------------------------- /include/stdlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | #define RAND_MAX (0x7fffffff) 6 | 7 | #define EXIT_SUCCESS 0 8 | #define EXIT_FAILURE 1 9 | 10 | int atoi(const char* s); 11 | long atol(const char* s); 12 | long long atoll(const char* s); 13 | void *malloc(size_t size); 14 | void free(void* ptr); 15 | void *realloc(void* ptr, size_t size); 16 | void *calloc(size_t size, size_t n); 17 | 18 | _Noreturn void exit(int code); 19 | int atexit(void (*func)(void)); 20 | 21 | long strtol(const char *p, char **pp, int base); 22 | unsigned long strtoul(const char *p, char **pp, int base); 23 | long long strtoll(const char *p, char **pp, int base); 24 | unsigned long long strtoull(const char *p, char **pp, int base); 25 | 26 | int abs(int x); 27 | long labs(long x); 28 | long long llabs(long long x); 29 | 30 | void qsort(void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *)); 31 | void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, 32 | int (*compare)(const void*, const void*)); 33 | 34 | int rand(void); // [0, RAND_MAX] 35 | void srand(unsigned int seed); 36 | 37 | #ifndef __NO_FLONUM 38 | double atof(const char *p); 39 | double strtod(const char* restrict p, char ** restrict pp); 40 | long double strtold(const char* restrict p, char ** restrict pp); 41 | double drand48(void); // [0.0, 1.0) 42 | double erand48(unsigned short xsubi[3]); // [0.0, 1.0) 43 | #endif 44 | long lrand48(void); // [0, 1<<31) 45 | long nrand48(unsigned short xsubi[3]); // [0, 1<<31) 46 | void srand48(long seedval); 47 | 48 | int mkstemp(char *tmpl); 49 | int mkstemps(char *tmpl, int suffixlen); 50 | 51 | char *getenv(const char *varname); 52 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define noreturn _Noreturn 4 | -------------------------------------------------------------------------------- /include/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | size_t strlen(const char *s); 6 | size_t strnlen(const char *s, size_t n); 7 | 8 | char *strchr(const char *s, int c); 9 | char *strrchr(const char *s, int c); 10 | char *strstr(const char *s1, const char *s2); 11 | 12 | int strcmp(const char *p, const char *q); 13 | int strncmp(const char *p, const char *q, size_t n); 14 | int strcoll(const char *p, const char *q); 15 | 16 | char *strcpy(char *dst, const char *src); 17 | char *strncpy(char *dst, const char *src, size_t n); 18 | 19 | char *stpcpy(char *dst, const char *src); 20 | char *stpncpy(char *dst, const char *src, size_t n); 21 | 22 | char *strcat(char *dst, const char *src); 23 | char *strncat(char *dst, const char *src, size_t n); 24 | 25 | char *strdup(const char *str); 26 | char *strndup(const char *str, size_t size); 27 | 28 | void *memcpy(void *dst, const void *src, size_t n); 29 | void *memccpy(void *dst, const void *src, int c, size_t n); 30 | void *memmove(void *dst, const void *src, size_t); 31 | void *memset(void *buf, int val, size_t size); 32 | void *memchr(const void *buf, int c, size_t n); 33 | int memcmp(const void *buf1, const void *buf2, size_t n); 34 | 35 | size_t strspn(const char *s, const char *accept); 36 | size_t strcspn(const char *s, const char *reject); 37 | char *strpbrk(const char *s, const char *accept); 38 | 39 | char *strerror(int no); 40 | int strerror_r(int no, char *dst, size_t n); 41 | 42 | char *strtok(char *src, const char *delim); 43 | char *strtok_r(char *src, const char *delim, char **ptr); 44 | -------------------------------------------------------------------------------- /include/strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | int strcasecmp(const char *p, const char *q); 6 | int strncasecmp(const char *p, const char *q, size_t n); 7 | -------------------------------------------------------------------------------- /include/sys/ioctl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NCC 8 4 | struct termio { 5 | unsigned short c_iflag; /* input mode flags */ 6 | unsigned short c_oflag; /* output mode flags */ 7 | unsigned short c_cflag; /* control mode flags */ 8 | unsigned short c_lflag; /* local mode flags */ 9 | unsigned char c_line; /* line discipline */ 10 | unsigned char c_cc[NCC]; /* control characters */ 11 | }; 12 | 13 | // /usr/include/asm-generic/ioctls.h 14 | #define TCGETA (0x5405) 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | int ioctl(int fd, int request, ...); 21 | 22 | #ifdef __cplusplus 23 | } // extern "C" 24 | #endif 25 | -------------------------------------------------------------------------------- /include/sys/random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // ssize_t 5 | 6 | #define GRND_NONBLOCK (0x0001) 7 | #define GRND_RANDOM (0x0002) 8 | 9 | ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); 10 | -------------------------------------------------------------------------------- /include/sys/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef long ssize_t; 4 | 5 | typedef int pid_t; 6 | typedef long off_t; 7 | -------------------------------------------------------------------------------- /include/sys/wait.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // pid_t 4 | 5 | #define _WSTOPPED 0x7f 6 | #define WTERMSIG(x) ((x) & 0x7f) 7 | #define WEXITSTATUS(x) ((x) >> 8) 8 | #define WIFEXITED(x) (WTERMSIG(x) == 0) 9 | #define WIFSIGNALED(x) (WTERMSIG(x) != _WSTOPPED && WTERMSIG(x) != 0) 10 | 11 | struct rusage; 12 | 13 | pid_t wait(int *status); 14 | pid_t waitpid(pid_t, int*, int); 15 | pid_t wait4(pid_t pid, int* status, int options, struct rusage *usage); 16 | -------------------------------------------------------------------------------- /include/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef long time_t; 4 | 5 | struct timespec { 6 | time_t tv_sec; 7 | long tv_nsec; 8 | }; 9 | 10 | typedef enum { 11 | CLOCK_REALTIME = 0, 12 | CLOCK_REALTIME_COARSE = 5, 13 | } clockid_t; 14 | 15 | time_t time(time_t *timer); 16 | int clock_gettime(clockid_t clk_id, struct timespec *tp); 17 | -------------------------------------------------------------------------------- /include/unistd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // intptr_t, uint64_t 5 | #include // ssize_t, pid_t, off_t 6 | 7 | #define STDIN_FILENO (0) 8 | #define STDOUT_FILENO (1) 9 | #define STDERR_FILENO (2) 10 | 11 | struct clone_args { 12 | uint64_t flags; /* Flags bit mask */ 13 | uint64_t pidfd; /* Where to store PID file descriptor 14 | (int *) */ 15 | uint64_t child_tid; /* Where to store child TID, 16 | in child's memory (pid_t *) */ 17 | uint64_t parent_tid; /* Where to store child TID, 18 | in parent's memory (pid_t *) */ 19 | uint64_t exit_signal; /* Signal to deliver to parent on 20 | child termination */ 21 | uint64_t stack; /* Pointer to lowest byte of stack */ 22 | uint64_t stack_size; /* Size of stack */ 23 | uint64_t tls; /* Location of new TLS */ 24 | uint64_t set_tid; /* Pointer to a pid_t array 25 | (since Linux 5.5) */ 26 | uint64_t set_tid_size; /* Number of elements in set_tid 27 | (since Linux 5.5) */ 28 | uint64_t cgroup; /* File descriptor for target cgroup 29 | of child (since Linux 5.7) */ 30 | }; 31 | 32 | ssize_t write(int fd, const void *str, size_t len); 33 | int close(int fd); 34 | ssize_t read(int fd, void *buf, size_t size); 35 | off_t lseek(int fd, off_t offset, int whence); 36 | int unlink(const char *pathname); 37 | int rmdir(const char *pathname); 38 | char *getcwd(char *buffer, size_t size); 39 | 40 | int brk(void *addr); 41 | void *sbrk(intptr_t increment); 42 | 43 | #if !defined(__WASM) 44 | int unlinkat(int dirfd, const char *pathname, int flags); 45 | int dup(int); 46 | int pipe(int *); 47 | int pipe2(int *pipefd, int flag); 48 | int isatty(int fd); 49 | int chdir(const char *path); 50 | 51 | pid_t fork(void); 52 | long clone3(struct clone_args *cl_args, size_t size); 53 | int execvp(const char *, char *const[]); 54 | int execve(const char *, char *const[], char *const[]); 55 | #endif 56 | -------------------------------------------------------------------------------- /include/wchar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _WCHAR_T_DEFINED 4 | #define _WCHAR_T_DEFINED 5 | typedef unsigned int wchar_t; 6 | #endif 7 | -------------------------------------------------------------------------------- /libsrc/.gitignore: -------------------------------------------------------------------------------- 1 | /file_test 2 | /longjmp_test 3 | /math_test 4 | /printf_test 5 | /stdlib_test 6 | 7 | *.wasm 8 | -------------------------------------------------------------------------------- /libsrc/_wasm/crt0/__main_void.c: -------------------------------------------------------------------------------- 1 | #include "alloca.h" 2 | 3 | #include "../wasi.h" 4 | 5 | extern int __main_argc_argv(int, char**); 6 | 7 | __attribute__((weak)) 8 | int __main_void(void) { 9 | char **argv; 10 | int argc, len; 11 | int r = args_sizes_get(&argc, &len); 12 | if (r == 0) { 13 | argv = alloca(sizeof(char*) * (argc + 1) + len); 14 | char *str = ((char*)argv) + sizeof(char*) * (argc + 1); 15 | args_get(argv, str); 16 | } else { // Ignore error. 17 | argc = 1; 18 | argv = alloca(sizeof(char*) * (argc + 1)); 19 | argv[0] = "*"; 20 | } 21 | argv[argc] = NULL; 22 | 23 | return __main_argc_argv(argc, argv); 24 | } 25 | -------------------------------------------------------------------------------- /libsrc/_wasm/crt0/_start.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" // exit 2 | 3 | #include "../wasi.h" 4 | 5 | extern void _start0(void); 6 | 7 | void _start(void) { 8 | _start0(); 9 | 10 | extern int __main_void(void); 11 | int ec = __main_void(); 12 | exit(ec); 13 | } 14 | -------------------------------------------------------------------------------- /libsrc/_wasm/crt0/_start0.c: -------------------------------------------------------------------------------- 1 | extern void __wasm_call_ctors(void); 2 | 3 | void _start0(void) { 4 | __wasm_call_ctors(); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/_detect_preopen.c: -------------------------------------------------------------------------------- 1 | #include "../wasi.h" 2 | 3 | int __max_preopen_fd = 3; 4 | 5 | __attribute__((constructor)) 6 | static void find_preopens(void) { 7 | for (int fd = 3; ; ++fd) { 8 | Prestat prestat; 9 | int result = fd_prestat_get(fd, &prestat); 10 | if (result != 0) { 11 | __max_preopen_fd = fd; 12 | return; 13 | } 14 | 15 | // char buf[256]; 16 | // fd_prestat_dir_name(fd, buf, prestat.u.dir.pr_name_len); // TODO: Confirm prestat.u.dir.pr_name_len < sizeof(buf) 17 | // buf[prestat.u.dir.pr_name_len] = '\0'; 18 | // fprintf(stderr, "preopens: %d, %s\n", fd, buf); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/_set_stat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "../wasi.h" 3 | 4 | void _set_stat(Filestat *fs, struct stat *st) { 5 | mode_t mode = 0; 6 | switch (fs->filetype) { 7 | case FILETYPE_BLOCK_DEVICE: mode = S_IFBLK; break; 8 | case FILETYPE_CHARACTER_DEVICE: mode = S_IFCHR; break; 9 | case FILETYPE_DIRECTORY: mode = S_IFDIR; break; 10 | case FILETYPE_REGULAR_FILE: mode = S_IFREG; break; 11 | case FILETYPE_SOCKET_DGRAM: mode = S_IFSOCK; break; 12 | case FILETYPE_SOCKET_STREAM: mode = S_IFSOCK; break; 13 | case FILETYPE_SYMBOLIC_LINK: mode = S_IFLNK; break; 14 | } 15 | 16 | st->st_dev = fs->dev; 17 | st->st_ino = fs->ino; 18 | st->st_mode = mode; 19 | st->st_nlink = fs->nlink; 20 | st->st_uid = 0; 21 | st->st_gid = 0; 22 | st->st_rdev = 0; 23 | st->st_size = fs->size; 24 | st->st_blksize = 0; 25 | st->st_blocks = 0; 26 | // TODO: atim, mtim, ctim 27 | } 28 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/brk.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "stdio.h" // EOF 3 | 4 | extern void *__curbrk; 5 | #define CURBRK __curbrk 6 | 7 | #define HEAP_ALIGN (8) 8 | #define MEMORY_PAGE_BIT (16) 9 | 10 | static void _growTo(void *ptr) { 11 | size_t page = (((size_t)ptr) + ((1 << MEMORY_PAGE_BIT) - 1)) >> MEMORY_PAGE_BIT; 12 | size_t count = __builtin_memory_size(); 13 | if (page > count) { 14 | const size_t grow = page - count; 15 | __builtin_memory_grow(grow); 16 | } 17 | } 18 | 19 | int brk(void *addr) { 20 | if (addr <= __curbrk) 21 | return EOF; 22 | void *p = (void*)((((intptr_t)addr) + (HEAP_ALIGN - 1)) & -HEAP_ALIGN); 23 | __curbrk = p; 24 | _growTo(p); 25 | return 0; 26 | } 27 | 28 | void *sbrk(intptr_t increment) { 29 | char *p = CURBRK; 30 | if (p == NULL) { 31 | if (brk(NULL) < 0) 32 | return (void*)-1; 33 | p = CURBRK; 34 | } 35 | char *next = p + increment; 36 | if (brk(next) < 0) 37 | return (void*)-1; 38 | return p; 39 | } 40 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/clock_gettime.c: -------------------------------------------------------------------------------- 1 | #include "time.h" 2 | #include "errno.h" 3 | #include "stddef.h" // NULL 4 | #include "stdint.h" 5 | #include "../wasi.h" 6 | 7 | int clock_gettime(clockid_t clk_id, struct timespec *tp) { 8 | if (tp == NULL) { 9 | errno = EINVAL; 10 | return -1; 11 | } 12 | 13 | uint64_t time; 14 | clock_time_get(clk_id, 1, &time); 15 | tp->tv_sec = time / 1000000000ULL; 16 | tp->tv_nsec = time % 1000000000ULL; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/close.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "../wasi.h" 3 | 4 | int close(int fd) { 5 | return fd_close(fd); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/fstat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "errno.h" 3 | #include "../wasi.h" 4 | 5 | extern void _set_stat(Filestat *fs, struct stat *st); 6 | 7 | int fstat(int fd, struct stat *st) { 8 | Filestat fs; 9 | uint32_t result = fd_filestat_get(fd, &fs); 10 | if (result == 0) { 11 | _set_stat(&fs, st); 12 | return 0; 13 | } 14 | errno = ENOENT; 15 | return -1; 16 | } 17 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/getcwd.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "stdlib.h" // malloc 4 | #include "string.h" // strlen 5 | 6 | const char *__cwd = "."; 7 | 8 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 9 | 10 | static inline size_t GETCWD(char *dst, size_t siz) { 11 | size_t _s = strlen(__cwd); 12 | size_t _m = MIN(_s + 1, siz); 13 | strncpy(dst, __cwd, _m); 14 | return _m; 15 | } 16 | 17 | char *getcwd(char *buffer, size_t size) { 18 | void *allocated = NULL; 19 | if (buffer == NULL) { 20 | if (size == 0) { 21 | size = 512; // PATH_MAX 22 | } 23 | buffer = allocated = malloc(size + 1); 24 | if (buffer == NULL) 25 | return NULL; 26 | } 27 | int result = GETCWD(buffer, size); 28 | if (result < 0) { 29 | errno = -result; 30 | free(allocated); 31 | return NULL; 32 | } 33 | return buffer; 34 | } 35 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/lseek.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "../wasi.h" 4 | 5 | off_t lseek(int fd, off_t offset, int whence) { 6 | size_t size; 7 | int result = fd_seek(fd, offset, whence, &size); 8 | if (result == 0) 9 | return size; 10 | errno = EIO; // TODO 11 | return -1; 12 | } 13 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/lstat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | 3 | int lstat(const char *fn, struct stat *st) { 4 | // TODO: Handle symbolic link? 5 | return stat(fn, st); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/mkdir.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "errno.h" 3 | #include "string.h" // memset, strncmp 4 | #include "../wasi.h" 5 | 6 | extern int __max_preopen_fd; 7 | 8 | int mkdir(const char *fn, mode_t mode) { 9 | (void)mode; 10 | size_t fnlen = strlen(fn); 11 | for (int base_fd = 3; base_fd < __max_preopen_fd; ++base_fd) { 12 | Prestat prestat; 13 | fd_prestat_get(base_fd, &prestat); 14 | size_t l = prestat.u.dir.pr_name_len; // Includes '\0' or not, depending on the environment, 15 | char buf[256]; 16 | fd_prestat_dir_name(base_fd, buf, l); 17 | buf[l] = '\0'; 18 | 19 | if ((*fn == '/' && *buf != '/') || 20 | (*fn != '/' && strcmp(buf, ".") != 0)) 21 | continue; 22 | 23 | const char *fn2 = fn; 24 | size_t fnlen2 = fnlen; 25 | 26 | if (strncmp(fn, buf, l) == 0 && fn[l] == '/') { 27 | fn2 = fn + (l + 1); 28 | fnlen2 = fnlen - (l + 1); 29 | } else if (l == 1 && *buf == '/' && *fn == '/') { 30 | fn2 = fn + 1; 31 | fnlen2 = fnlen - 1; 32 | } 33 | 34 | uint32_t result = path_create_directory(base_fd, fn2, fnlen2); 35 | if (result == 0) 36 | return 0; 37 | } 38 | errno = EPERM; // TODO 39 | return -1; 40 | } 41 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/read.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "../wasi.h" 4 | 5 | ssize_t read(int fd, void *buf, size_t size) { 6 | Iov iov; 7 | iov.str = buf; 8 | iov.n = size; 9 | size_t readed; 10 | int result = fd_read(fd, &iov, 1, &readed); 11 | if (result == 0) 12 | return readed; 13 | errno = EIO; // TODO 14 | return -1; 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/rmdir.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "string.h" 4 | #include "../wasi.h" 5 | 6 | extern int __max_preopen_fd; 7 | 8 | int rmdir(const char *fn) { 9 | // Search from preopens 10 | size_t fnlen = strlen(fn); 11 | for (int base_fd = 3; base_fd < __max_preopen_fd; ++base_fd) { 12 | Prestat prestat; 13 | if (fd_prestat_get(base_fd, &prestat) != 0) 14 | break; 15 | 16 | size_t l = prestat.u.dir.pr_name_len; // Includes '\0' or not, depending on the environment, 17 | char buf[256]; 18 | fd_prestat_dir_name(base_fd, buf, l); 19 | buf[l] = '\0'; 20 | 21 | if ((*fn == '/' && *buf != '/') || 22 | (*fn != '/' && strcmp(buf, ".") != 0)) 23 | continue; 24 | 25 | const char *fn2 = fn; 26 | size_t fnlen2 = fnlen; 27 | 28 | if (strncmp(fn, buf, l) == 0 && fn[l] == '/') { 29 | fn2 = fn + (l + 1); 30 | fnlen2 = fnlen - (l + 1); 31 | } else if (l == 1 && *buf == '/' && *fn == '/') { 32 | fn2 = fn + 1; 33 | fnlen2 = fnlen - 1; 34 | } 35 | int result = path_remove_directory(base_fd, fn2, fnlen2); 36 | if (result == 0) 37 | return 0; 38 | } 39 | errno = ENOENT; 40 | return -1; 41 | } 42 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/stat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "errno.h" 3 | #include "string.h" // memset, strncmp 4 | #include "../wasi.h" 5 | 6 | extern int __max_preopen_fd; 7 | 8 | extern void _set_stat(Filestat *fs, struct stat *st); 9 | 10 | int stat(const char *fn, struct stat *st) { 11 | memset(st, 0, sizeof(st)); 12 | size_t fnlen = strlen(fn); 13 | for (int base_fd = 3; base_fd < __max_preopen_fd; ++base_fd) { 14 | Prestat prestat; 15 | fd_prestat_get(base_fd, &prestat); 16 | size_t l = prestat.u.dir.pr_name_len; // Includes '\0' or not, depending on the environment, 17 | char buf[256]; 18 | fd_prestat_dir_name(base_fd, buf, l); 19 | buf[l] = '\0'; 20 | 21 | if ((*fn == '/' && *buf != '/') || 22 | (*fn != '/' && strcmp(buf, ".") != 0)) 23 | continue; 24 | 25 | const char *fn2 = fn; 26 | size_t fnlen2 = fnlen; 27 | 28 | if (strncmp(fn, buf, l) == 0 && fn[l] == '/') { 29 | fn2 = fn + (l + 1); 30 | fnlen2 = fnlen - (l + 1); 31 | } else if (l == 1 && *buf == '/' && *fn == '/') { 32 | fn2 = fn + 1; 33 | fnlen2 = fnlen - 1; 34 | } 35 | 36 | Filestat fs; 37 | uint32_t result = path_filestat_get(base_fd, 0, fn2, fnlen2, &fs); 38 | if (result == 0) { 39 | _set_stat(&fs, st); 40 | return 0; 41 | } 42 | } 43 | errno = ENOENT; 44 | return -1; 45 | } 46 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/time.c: -------------------------------------------------------------------------------- 1 | #include "time.h" 2 | #include "stddef.h" // NULL 3 | #include "stdint.h" 4 | #include "../wasi.h" 5 | 6 | time_t time(time_t *timer) { 7 | uint64_t t; 8 | clock_time_get(CLOCK_REALTIME, 100000000ULL, &t); 9 | uint64_t sec = t / 1000000000ULL; 10 | if (timer != NULL) 11 | *timer = sec; 12 | return sec; 13 | } 14 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/unlink.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "string.h" 4 | #include "../wasi.h" 5 | 6 | extern int __max_preopen_fd; 7 | 8 | int unlink(const char *fn) { 9 | // Search from preopens 10 | size_t fnlen = strlen(fn); 11 | for (int base_fd = 3; base_fd < __max_preopen_fd; ++base_fd) { 12 | Prestat prestat; 13 | if (fd_prestat_get(base_fd, &prestat) != 0) 14 | break; 15 | 16 | size_t l = prestat.u.dir.pr_name_len; // Includes '\0' or not, depending on the environment, 17 | char buf[256]; 18 | fd_prestat_dir_name(base_fd, buf, l); 19 | buf[l] = '\0'; 20 | 21 | if ((*fn == '/' && *buf != '/') || 22 | (*fn != '/' && strcmp(buf, ".") != 0)) 23 | continue; 24 | 25 | const char *fn2 = fn; 26 | size_t fnlen2 = fnlen; 27 | 28 | if (strncmp(fn, buf, l) == 0 && fn[l] == '/') { 29 | fn2 = fn + (l + 1); 30 | fnlen2 = fnlen - (l + 1); 31 | } else if (l == 1 && *buf == '/' && *fn == '/') { 32 | fn2 = fn + 1; 33 | fnlen2 = fnlen - 1; 34 | } 35 | int result = path_unlink_file(base_fd, fn2, fnlen2); 36 | if (result == 0) 37 | return 0; 38 | } 39 | errno = ENOENT; // TODO 40 | return -1; 41 | } 42 | -------------------------------------------------------------------------------- /libsrc/_wasm/unistd/write.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "../wasi.h" 4 | 5 | ssize_t write(int fd, const void *str, size_t len) { 6 | Iov iov; 7 | iov.str = str; 8 | iov.n = len; 9 | size_t written; 10 | int result = fd_write(fd, &iov, 1, &written); 11 | if (result == 0) 12 | return written; 13 | errno = EIO; // TODO 14 | return -1; 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/crt0/_start.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" // atexit, exit 2 | #include "../stdlib/_exit.h" 3 | 4 | #if defined(__GNUC__) 5 | #pragma GCC diagnostic ignored "-Wunused-function" 6 | #endif 7 | 8 | #if defined(__linux__) 9 | extern void (*__init_array_start []) (void); // __attribute__((weak)); 10 | extern void (*__init_array_end []) (void); // __attribute__((weak)); 11 | extern void (*__fini_array_start []) (void); // __attribute__((weak)); 12 | extern void (*__fini_array_end []) (void); // __attribute__((weak)); 13 | 14 | static void call_fini_funcs(void) { 15 | for (void (**pp)(void) = __fini_array_start; pp < __fini_array_end; ++pp) 16 | (*pp)(); 17 | } 18 | 19 | static void start2(int argc, char *argv[], char *env[]) { 20 | extern int main(int, char**, char**); 21 | #ifndef __APPLE__ 22 | extern char **environ; 23 | environ = env; 24 | #endif 25 | 26 | static OnExitChain chain = {NULL, call_fini_funcs}; 27 | chain.next = __on_exit_chain; 28 | __on_exit_chain = &chain; 29 | 30 | for (void (**pp)(void) = __init_array_start; pp < __init_array_end; ++pp) 31 | (*pp)(); 32 | 33 | int ec = main(argc, argv, env); 34 | exit(ec); 35 | } 36 | 37 | void _start(void) { 38 | (void)start2; // Avoid warning: unused function 'start2' 39 | #if defined(__x86_64__) 40 | __asm("mov (%rsp), %rdi\n" 41 | "lea 8(%rsp), %rsi\n" 42 | "lea 8(%rsi, %rdi, 8), %rdx\n" 43 | "jmp start2"); 44 | #elif defined(__aarch64__) 45 | __asm("ldr x0, [sp]\n" 46 | "add x1, sp, #8\n" 47 | "add x2, x1, #8\n" 48 | "add x2, x2, x0, lsl #3\n" 49 | "b start2"); 50 | #elif defined(__riscv) 51 | __asm("lw a0, 0(sp)\n" // argc 52 | "addi a1, sp, 8\n" // argv 53 | "slli a2, a0, 3\n" 54 | "addi a2, a2, 8\n" 55 | "add a2, a2, a1\n" // envp 56 | "j start2\n"); 57 | #else 58 | #error unknown target 59 | #endif 60 | } 61 | 62 | #elif defined(__APPLE__) 63 | 64 | // Use libc. 65 | 66 | extern void exit(int code); 67 | 68 | #else 69 | #error Target not supported 70 | #endif 71 | -------------------------------------------------------------------------------- /libsrc/math/_ieee.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdint.h" // int64_t 4 | 5 | // double: Sign(1):Exponent(11):Fraction(52) 6 | 7 | #define FRAC_BIT (52) // Fraction (significand in other words) 8 | #define EXPO_POS FRAC_BIT 9 | #define EXPO_BIT (11) 10 | #define EXPO_BIAS (1022) 11 | #define SIGN_POS (FRAC_BIT + EXPO_BIT) 12 | 13 | #define FRAC_MASK (((int64_t)1 << FRAC_BIT) - 1) 14 | #define EXPO_MASK ((((int64_t)1 << EXPO_BIT) - 1) << EXPO_POS) 15 | #define SIGN_MASK ((int64_t)1 << SIGN_POS) 16 | 17 | #define NAN_MASK ((((int64_t)1 << (EXPO_BIT + 1)) - 1) << (EXPO_POS - 1)) 18 | 19 | #define GET_EXPO(hex) (GET_BIASED_EXPO(hex) - EXPO_BIAS) 20 | #define GET_BIASED_EXPO(hex) (((int)((hex) >> EXPO_POS)) & ((1 << EXPO_BIT) - 1)) 21 | -------------------------------------------------------------------------------- /libsrc/math/_normalize_radian.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double _normalize_radian(double x) { 5 | double y = fmod(x, 2 * M_PI); 6 | if (y > M_PI) 7 | return y - 2 * M_PI; 8 | if (y < -M_PI) 9 | return y + 2 * M_PI; 10 | return y; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /libsrc/math/acos.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double acos(double x) { 5 | if (x < -1 || x > 1 || !isfinite(x)) 6 | return NAN; 7 | return M_PI_2 - asin(x); 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /libsrc/math/acosh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double acosh(double x) { 5 | if (x < 1) 6 | return NAN; 7 | return log(x + sqrt(x * x - 1)); 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /libsrc/math/asin.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double asin(double x) { 5 | if (x < -1 || x > 1 || !isfinite(x)) 6 | return NAN; 7 | if (x < 0) 8 | return -asin(-x); 9 | 10 | if (x <= 0.5) { 11 | double v = x; 12 | double k = x; 13 | double xx = x * x; 14 | for (int i = 0; i < 12; ++i) { 15 | int n = i + 1; 16 | k *= xx * (double)(2 * n - 1) / (double)(2 * n); 17 | v += k / (2 * n + 1); 18 | } 19 | return v; 20 | } else { 21 | // Derived from half angle formula of sin. 22 | return M_PI_2 - 2 * asin(sqrt((1 - x) * 0.5)); 23 | } 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/math/asinh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double asinh(double x) { 5 | return log(x + sqrt(x * x + 1)); 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/math/atan.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdbool.h" 3 | 4 | #ifndef __NO_FLONUM 5 | #define TAN225 0.414213562373095 // tan(22.5 degree) 6 | 7 | double atan(double x) { 8 | bool neg = x < 0; 9 | x = fabs(x); 10 | bool inv = false; 11 | if (x > 1) { 12 | x = 1.0 / x; 13 | inv = true; 14 | } 15 | bool diag = false; 16 | if (x > TAN225) { 17 | x = (1 - x) / (1 + x); 18 | diag = true; 19 | } 20 | 21 | double t = 0; 22 | { 23 | double _xx = -x * x; 24 | double k = x; 25 | for (int i = 0; i < 16; ++i) { 26 | t += k / (i * 2 + 1); 27 | k *= _xx; 28 | } 29 | } 30 | 31 | if (diag) 32 | t = (M_PI / 4) - t; 33 | if (inv) 34 | t = (M_PI / 2) - t; 35 | return neg ? -t : t; 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /libsrc/math/atan2.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdbool.h" 3 | 4 | #ifndef __NO_FLONUM 5 | double atan2(double y, double x) { 6 | if (fabs(x) >= fabs(y)) { 7 | if (x == 0) 8 | return signbit(x) == 0 ? y : copysign(M_PI, y); 9 | double t = atan(y / x); 10 | if (x < 0) 11 | t = (t <= 0 ? M_PI : -M_PI) + t; 12 | return t; 13 | } else { 14 | double t = atan(x / y); 15 | t = (y >= 0 ? M_PI / 2 : -M_PI / 2) - t; 16 | return t; 17 | } 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /libsrc/math/atanh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double atanh(double x) { 5 | if (x > 1 || x < -1) 6 | return NAN; 7 | return 0.5 * log((1 + x) / (1 - x)); 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /libsrc/math/ceil.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double ceil(double x) { 7 | #if defined(__WASM) 8 | #define S(x) S_(x) 9 | #define S_(x) #x 10 | #define OP_LOCAL_GET 32 // 0x20 11 | #define OP_F64_CEIL 155 // 0x9b 12 | __asm( 13 | S(OP_LOCAL_GET) ",0," // local.get 0 14 | S(OP_F64_CEIL)); // f64.ceil 15 | #else 16 | int64_t q = *(int64_t*)&x; 17 | int e = GET_BIASED_EXPO(q); 18 | if (e <= EXPO_BIAS + FRAC_BIT && e != 0) { 19 | if (e <= EXPO_BIAS) 20 | return q > 0 ? 1.0 : 0.0; 21 | 22 | int64_t one = (int64_t)1 << ((EXPO_BIAS + FRAC_BIT + 1) - e); 23 | if (q < 0) { 24 | int64_t r = q & -one; 25 | return *(double*)&r; 26 | } else { 27 | int64_t frac = q & (one - 1); 28 | if (frac != 0) { 29 | int64_t r = (q & -one) + one; 30 | return *(double*)&r; 31 | } 32 | } 33 | } 34 | return x; 35 | #endif 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /libsrc/math/copysign.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double copysign(double x, double f) { 7 | #if defined(__WASM) 8 | #define S(x) S_(x) 9 | #define S_(x) #x 10 | #define OP_LOCAL_GET 32 // 0x20 11 | #define OP_F64_COPYSIGN 166 // 0xa6 12 | __asm( 13 | S(OP_LOCAL_GET) ",0," // local.get 0 14 | S(OP_LOCAL_GET) ",1," // local.get 1 15 | S(OP_F64_COPYSIGN)); // f64.copysign 16 | #elif defined(__riscv) && !defined(__GNUC__) 17 | __asm("fsgnj.d fa0, fa0, fa1"); 18 | #else 19 | union { double d; int64_t q; } u; 20 | u.d = x; 21 | u.q = (u.q & ~SIGN_MASK) | ((uint64_t)signbit(f) << SIGN_POS); 22 | return u.d; 23 | #endif 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/math/cos.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | extern double _normalize_radian(double x); 5 | 6 | double cos(double x) { 7 | static const double TABLE[] = { 8 | 1 / 1.0, 9 | -1 / (2.0 * 1), 10 | 1 / (4.0 * 3 * 2 * 1), 11 | -1 / (6.0 * 5 * 4 * 3 * 2 * 1), 12 | 1 / (8.0 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 13 | -1 / (10.0 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 14 | 1 / (12.0 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 15 | -1 / (14.0 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 16 | 1 / (16.0 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 17 | -1 / (18.0 * 17 * 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 18 | }; 19 | 20 | x = _normalize_radian(x); 21 | 22 | double v = 0; 23 | double xx = x * x; 24 | x = 1; 25 | for (int i = 0; i < (int)(sizeof(TABLE) / sizeof(*TABLE)); ++i) { 26 | v += x * TABLE[i]; 27 | x *= xx; 28 | } 29 | return v; 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /libsrc/math/cosh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double cosh(double x) { 5 | // (e^x + e^-x) / 2 6 | return (exp(x) + exp(-x)) * 0.5; 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /libsrc/math/exp.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdbool.h" 3 | 4 | #ifndef __NO_FLONUM 5 | double exp(double x) { 6 | bool neg = x < 0; 7 | x = fabs(x); 8 | unsigned int n = x; // TODO: Care about overflow 9 | double r = (x - n) /* * log(base)*/; // log(e) = 1 10 | 11 | double result = 1; 12 | double y = 1; 13 | for (int i = 1; i <= 15; ++i) { 14 | y *= r / i; 15 | result += y; 16 | } 17 | 18 | double poe = M_E; 19 | for (; n > 0; n >>= 1, poe *= poe) { 20 | if (n & 1) 21 | result *= poe; 22 | } 23 | return neg ? 1.0 / result : result; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/math/fabs.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double fabs(double x) { 7 | union { double d; int64_t q; } u; 8 | u.d = x; 9 | u.q &= ~SIGN_MASK; 10 | return u.d; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /libsrc/math/fabsf.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | float fabsf(float x) { 7 | union { float f; int32_t l; } u; 8 | u.f = x; 9 | u.l &= (int32_t)~(1 << 31); 10 | return u.f; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /libsrc/math/finite.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | extern inline int isfinite(double x); 7 | 8 | int finite(double x) { 9 | union { double d; int64_t q; } u; 10 | u.d = x; 11 | return (u.q & EXPO_MASK) != EXPO_MASK; 12 | } 13 | 14 | #if defined(__APPLE__) 15 | int __isfinited(double x) { return finite(x); } 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /libsrc/math/floor.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double floor(double x) { 7 | #if defined(__WASM) 8 | #define S(x) S_(x) 9 | #define S_(x) #x 10 | #define OP_LOCAL_GET 32 // 0x20 11 | #define OP_F64_FLOOR 156 // 0x9c 12 | __asm( 13 | S(OP_LOCAL_GET) ",0," // local.get 0 14 | S(OP_F64_FLOOR)); // f64.floor 15 | #else 16 | int64_t q = *(int64_t*)&x; 17 | int e = GET_BIASED_EXPO(q); 18 | if (e <= EXPO_BIAS + FRAC_BIT && e != 0) { 19 | if (e <= EXPO_BIAS) 20 | return q >= 0 ? 0.0 : -1.0; 21 | 22 | int64_t one = (int64_t)1 << ((EXPO_BIAS + FRAC_BIT + 1) - e); 23 | if (q > 0) { 24 | int64_t r = q & -one; 25 | return *(double*)&r; 26 | } else { 27 | int64_t frac = q & (one - 1); 28 | if (frac != 0) { 29 | int64_t r = (q & -one) + one; 30 | return *(double*)&r; 31 | } 32 | } 33 | } 34 | return x; 35 | #endif 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /libsrc/math/fmod.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double fmod(double x, double m) { 5 | m = fabs(m); 6 | if (x >= 0) 7 | return x - floor(x / m) * m; 8 | else 9 | return x - ceil(x / m) * m; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/math/fpclassify.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "float.h" 3 | 4 | #ifndef __NO_FLONUM 5 | extern int __isnan(double); 6 | extern int __isinf(double); 7 | 8 | #if defined(__riscv) 9 | #define __fpclassify __fpclassifyd 10 | #endif 11 | 12 | int __fpclassify(double x) { 13 | if (!finite(x)) 14 | return __isnan(x) ? FP_NAN : FP_INFINITE; 15 | if (x == 0.0) 16 | return FP_ZERO; 17 | if (x < DBL_MIN && x > -DBL_MIN) 18 | return FP_SUBNORMAL; 19 | return FP_NORMAL; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /libsrc/math/frexp.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double frexp(double x, int *p) { 7 | if (!isfinite(x) || x == 0) { 8 | *p = 0; 9 | return x; 10 | } 11 | int64_t q = *(int64_t*)&x; 12 | *p = GET_EXPO(q); 13 | int64_t r = (q & (FRAC_MASK | SIGN_MASK)) | ((int64_t)EXPO_BIAS << EXPO_POS); 14 | return *(double*)&r; 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /libsrc/math/isinf.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | extern inline int isinf(double x); 7 | 8 | int __isinf(double x) { 9 | union { double d; int64_t q; } u; 10 | u.d = x; 11 | return (u.q & NAN_MASK) == EXPO_MASK; 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libsrc/math/isnan.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | extern inline int isnan(double x); 7 | 8 | int __isnan(double x) { 9 | union { double d; int64_t q; } u; 10 | u.d = x; 11 | return (u.q & NAN_MASK) == NAN_MASK; 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libsrc/math/ldexp.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double ldexp(double x, int exp) { 7 | if (!isfinite(x) || x == 0) { 8 | return x; 9 | } 10 | int64_t q = *(int64_t*)&x; 11 | exp += GET_BIASED_EXPO(q); 12 | if (exp >= ((1 << EXPO_BIT) - 1)) 13 | return x < 0 ? -HUGE_VAL : HUGE_VAL; 14 | else if (exp < 0) 15 | return 0; 16 | int64_t r = (q & (FRAC_MASK | SIGN_MASK)) | ((int64_t)exp << EXPO_POS); 17 | return *(double*)&r; 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /libsrc/math/log.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double log(double x) { 5 | if (x <= 0) 6 | return x < 0 ? NAN : -HUGE_VAL; 7 | if (!isfinite(x)) 8 | return x; 9 | 10 | int n; 11 | x = frexp(x, &n); 12 | // 0.5 <= x < 1.0 13 | 14 | double y = (x - 1) / (x + 1); 15 | double yy = y * y; 16 | double total = 0; 17 | for (int i = 1; i <= 15; ++i) { 18 | total += y / (i * 2 - 1); 19 | y *= yy; 20 | } 21 | return 2 * total + n * M_LN2; 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /libsrc/math/log10.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double log10(double x) { 5 | if (x <= 0) 6 | return x < 0 ? NAN : -HUGE_VAL; 7 | if (!isfinite(x)) 8 | return x; 9 | 10 | return log(x) * (1.0 / M_LN10); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /libsrc/math/log2.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double log2(double x) { 5 | if (x <= 0) 6 | return x < 0 ? NAN : -HUGE_VAL; 7 | if (!isfinite(x)) 8 | return x; 9 | 10 | return log(x) * (1.0 / M_LN2); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /libsrc/math/modf.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double modf(double x, double *pint) { 5 | if (!isfinite(x)) { 6 | *pint = x; 7 | return isnan(x) ? x : 0.0; 8 | } 9 | 10 | double i = x >= 0 ? floor(x) : ceil(x); 11 | *pint = i; 12 | return x - i; 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /libsrc/math/pow.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdbool.h" 3 | 4 | #ifndef __NO_FLONUM 5 | double pow(double base, double x) { 6 | bool neg = x < 0; 7 | x = fabs(x); 8 | unsigned int n = x; // TODO: Care about overflow 9 | double r = (x - n) * log(base); 10 | 11 | double result = 1; 12 | double y = 1; 13 | for (int i = 1; i <= 15; ++i) { 14 | y *= r / i; 15 | result += y; 16 | } 17 | 18 | double poe = base; 19 | for (; n > 0; n >>= 1, poe *= poe) { 20 | if (n & 1) 21 | result *= poe; 22 | } 23 | return neg ? 1.0 / result : result; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/math/round.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | double round(double x) { 7 | return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /libsrc/math/signbit.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | #include "stdint.h" // int64_t 3 | #include "_ieee.h" 4 | 5 | #ifndef __NO_FLONUM 6 | extern inline int signbit(double x); 7 | 8 | #if defined(__APPLE__) || defined(__riscv) 9 | #define __signbit __signbitd 10 | #endif 11 | 12 | int __signbit(double x) { 13 | return ((*(uint64_t*)&x) >> (EXPO_POS + EXPO_BIT)); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /libsrc/math/sin.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | extern double _normalize_radian(double x); 5 | 6 | double sin(double x) { 7 | static const double TABLE[] = { 8 | 1 / 1.0, 9 | -1 / (3.0 * 2 * 1), 10 | 1 / (5.0 * 4 * 3 * 2 * 1), 11 | -1 / (7.0 * 6 * 5 * 4 * 3 * 2 * 1), 12 | 1 / (9.0 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 13 | -1 / (11.0 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 14 | 1 / (13.0 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 15 | -1 / (15.0 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 16 | 1 / (17.0 * 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 17 | -1 / (19.0 * 18 * 17 * 16 * 15 * 14 * 13 * 12 * 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1), 18 | }; 19 | 20 | x = _normalize_radian(x); 21 | 22 | double v = 0; 23 | double xx = x * x; 24 | for (int i = 0; i < (int)(sizeof(TABLE) / sizeof(*TABLE)); ++i) { 25 | v += x * TABLE[i]; 26 | x *= xx; 27 | } 28 | return v; 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /libsrc/math/sinh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double sinh(double x) { 5 | // (e^x - e^-x) / 2 6 | return (exp(x) - exp(-x)) * 0.5; 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /libsrc/math/sqrt.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double sqrt(double x) { 5 | #if defined(__WASM) 6 | #define S(x) S_(x) 7 | #define S_(x) #x 8 | #define OP_LOCAL_GET 32 // 0x20 9 | #define OP_F64_SQRT 159 // 0x9f 10 | __asm( 11 | S(OP_LOCAL_GET) ",0," // local.get 0 12 | S(OP_F64_SQRT)); // f64.sqrt 13 | #elif defined(__x86_64__) && !defined(__GNUC__) 14 | __asm("sqrtsd %xmm0, %xmm0"); 15 | #elif defined(__aarch64__) && !defined(__GNUC__) 16 | __asm("fsqrt d0, d0"); 17 | #elif defined(__riscv) && !defined(__GNUC__) 18 | __asm("fsqrt.d fa0, fa0"); 19 | #else 20 | if (x < 0) 21 | return NAN; 22 | if (!isfinite(x)) // NAN or HUGE_VAL 23 | return x; 24 | 25 | double l = 0, r = x >= 1 ? x : 1.0; 26 | for (int i = 0; i < 32; ++i) { 27 | double m = (l + r) * 0.5; 28 | double mm = m * m; 29 | if (mm < x) 30 | l = m; 31 | else 32 | r = m; 33 | } 34 | return (l + r) * 0.5; 35 | #endif 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /libsrc/math/tan.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double tan(double x) { 5 | return sin(x) / cos(x); // TODO; 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/math/tanh.c: -------------------------------------------------------------------------------- 1 | #include "math.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double tanh(double x) { 5 | return sinh(x) / cosh(x); 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/misc/basename.c: -------------------------------------------------------------------------------- 1 | #include "libgen.h" 2 | #include "string.h" // strrchr 3 | 4 | char *basename(char *path) { 5 | char *p = strrchr(path, '/'); 6 | if (p != NULL) 7 | return p + 1; 8 | else 9 | return path; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/misc/dirname.c: -------------------------------------------------------------------------------- 1 | #include "libgen.h" 2 | #include "string.h" // strrchr 3 | 4 | char *dirname(char *path) { 5 | char *p = strrchr(path, '/'); 6 | if (p != NULL) { 7 | *p = '\0'; 8 | return path; 9 | } 10 | return "."; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/misc/errno.c: -------------------------------------------------------------------------------- 1 | #if defined(__riscv) 2 | int errno; 3 | 4 | #else 5 | 6 | #if defined(__APPLE__) 7 | #define __errno_location __error 8 | #endif 9 | int *__errno_location(void) { 10 | static int value; 11 | return &value; 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libsrc/misc/isalnum.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isalnum(int c) { 4 | return isalpha(c) || isdigit(c); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isalpha.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isalpha(int c) { 4 | return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isascii.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isascii(int c) { 4 | return (unsigned int)c <= 0x7f; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/iscntrl.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int iscntrl(int c) { 4 | return (0 <= c && c <= 0x1f) || c == 0x7f; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isdigit.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isdigit(int c) { 4 | return '0' <= c && c <= '9'; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isgraph.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isgraph(int c) { 4 | return 0x21 <= c && c <= 0x7e; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/islower.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int islower(int c) { 4 | return 'a' <= c && c <= 'z'; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isprint.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isprint(int c) { 4 | return 0x20 <= c && c <= 0x7e; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/ispunct.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int ispunct(int c) { 4 | return isgraph(c) && !isalnum(c); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isspace.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isspace(int c) { 4 | return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || 5 | c == '\f' || c == '\v'); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/misc/isupper.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isupper(int c) { 4 | return 'A' <= c && c <= 'Z'; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/isxdigit.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int isxdigit(int c) { 4 | return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/tolower.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int tolower(int c) { 4 | return isupper(c) ? c + ('a' - 'A') : c; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/misc/toupper.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int toupper(int c) { 4 | return islower(c) ? c - ('a' - 'A') : c; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdio/_detect_open_flag.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "fcntl.h" // O_ACCMODE, etc. 4 | 5 | int _detect_open_flag(const char *mode) { 6 | enum Chr { 7 | RWMASK = 3, 8 | R = 1 | (1 << 5), 9 | W = 2 | (1 << 5), 10 | P = 1 << 2, 11 | MASK = 7, 12 | A = 1 << 3, 13 | B = 1 << 4, 14 | }; 15 | enum Err { 16 | OK, 17 | CONFLICT, 18 | ILLEGAL_CHR, 19 | }; 20 | 21 | int chr = 0, c = 0; 22 | enum Err err = OK; 23 | for (const char *p = mode; (c = *p) != '\0'; ++p) { 24 | switch (c) { 25 | case 'r': c = R; break; 26 | case 'w': c = W; break; 27 | case 'a': c = W | A; break; 28 | case '+': c = P; break; 29 | case 'b': c = B; break; 30 | default: err = ILLEGAL_CHR; break; 31 | } 32 | if (err != OK || ((chr & c) != 0 && (err = CONFLICT, 1))) 33 | break; 34 | chr |= c; 35 | } 36 | switch (err) { 37 | case OK: default: 38 | break; 39 | case CONFLICT: 40 | fprintf(stderr, "conflict: %c\n", c); 41 | return -1; 42 | case ILLEGAL_CHR: 43 | fprintf(stderr, "illegal character: %c\n", c); 44 | return -1; 45 | } 46 | if ((chr & RWMASK) == 0) { 47 | fprintf(stderr, "r|w|a required\n"); 48 | return -1; 49 | } 50 | 51 | static const int kTable[] = { 52 | [R & MASK] = O_RDONLY, 53 | [W & MASK] = O_WRONLY | O_CREAT, 54 | [(R | P) & MASK] = O_RDWR, 55 | [(W | P) & MASK] = O_RDWR | O_CREAT, 56 | }; 57 | int flag = kTable[chr & MASK]; 58 | if ((chr & RWMASK) == (W & RWMASK)) 59 | flag |= (chr & A) ? O_APPEND : O_TRUNC; 60 | return flag; 61 | } 62 | -------------------------------------------------------------------------------- /libsrc/stdio/_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stddef.h" // size_t 4 | #include "sys/types.h" // ssize_t, off64_t 5 | 6 | #define FF_BINARY (1 << 0) 7 | #define FF_READ (1 << 1) 8 | #define FF_WRITE (1 << 2) 9 | #define FF_EOF (1 << 3) 10 | #define FF_GROWMEM (1 << 4) 11 | #define FF_FIFO (1 << 5) 12 | #define FF_INITIALIZED (1 << 15) 13 | 14 | typedef ssize_t (*cookie_read_function_t)(void *cookie, char *buf, size_t size); 15 | typedef ssize_t (*cookie_write_function_t)(void *cookie, const char *buf, size_t size); 16 | typedef int (*cookie_seek_function_t)(void *cookie, off_t *offset, int whence); 17 | typedef int (*cookie_close_function_t)(void *cookie); 18 | 19 | typedef struct { 20 | cookie_read_function_t read; 21 | cookie_write_function_t write; 22 | cookie_seek_function_t seek; 23 | cookie_close_function_t close; 24 | } cookie_io_functions_t; 25 | 26 | struct FILE { 27 | const cookie_io_functions_t *iof; // not struct but const pointer. 28 | int (*flush)(struct FILE *fp); 29 | unsigned char *wbuf; 30 | unsigned char *rbuf; 31 | 32 | int fd; 33 | unsigned int rp, rs, rcapa; 34 | unsigned int wp, wcapa; 35 | unsigned int flag; 36 | int unget_char; 37 | }; 38 | 39 | extern ssize_t _fread(void *cookie, char *buf, size_t total); 40 | extern ssize_t _fwrite(void *cookie, const char *buf, size_t size); 41 | extern int _fseek(void *cookie, off_t *offset, int origin); 42 | extern int _fflush(FILE *fp); 43 | 44 | extern void _add_opened_file(FILE *fp); 45 | extern void _remove_opened_file(FILE *fp); 46 | extern int _detect_open_flag(const char *mode); 47 | 48 | static inline int _fputc(int c, FILE *fp) { 49 | unsigned char _buf = c; 50 | ssize_t _result = (fp->iof->write)(fp, (char*)&_buf, sizeof(_buf)); 51 | return _result == sizeof(_buf) ? (int)_buf : EOF; 52 | } 53 | -------------------------------------------------------------------------------- /libsrc/stdio/_fileman.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "stdlib.h" // realloc 4 | 5 | #include "_file.h" 6 | #include "_fileman.h" 7 | 8 | #define INITIAL_CAPACITY (4) 9 | 10 | FILEMAN __fileman; 11 | 12 | void _add_opened_file(FILE *fp) { 13 | if (__fileman.length >= __fileman.capacity) { 14 | int ncapa = __fileman.capacity > 0 ? __fileman.capacity << 1 : INITIAL_CAPACITY; 15 | FILE **buf = realloc(__fileman.opened, ncapa * sizeof(*__fileman.opened)); 16 | if (buf == NULL) { 17 | // TODO: 18 | fputs("Out of memory\n", stderr); 19 | exit(1); 20 | } 21 | __fileman.opened = buf; 22 | __fileman.capacity = ncapa; 23 | } 24 | __fileman.opened[__fileman.length++] = fp; 25 | } 26 | 27 | void _remove_opened_file(FILE *fp) { 28 | FILE **files = __fileman.opened; 29 | for (int i = 0, length = __fileman.length; i < length; ++i) { 30 | if (files[i] == fp) { 31 | --length; 32 | if (i < length) { 33 | // Swap to the last. 34 | files[i] = files[length]; 35 | } 36 | __fileman.length = length; 37 | break; 38 | } 39 | } 40 | } 41 | 42 | __attribute__((destructor)) 43 | static void flush_opened_files(void) { 44 | struct FILE **files = __fileman.opened; 45 | for (int i = 0, length = __fileman.length; i < length; ++i) { 46 | FILE *fp = files[i]; 47 | (fp->flush)(fp); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libsrc/stdio/_fileman.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct FILE; 4 | 5 | typedef struct { 6 | struct FILE **opened; 7 | int length, capacity; 8 | } FILEMAN; 9 | -------------------------------------------------------------------------------- /libsrc/stdio/assert.c: -------------------------------------------------------------------------------- 1 | #include "assert.h" 2 | #include "stdio.h" 3 | #include "stdlib.h" 4 | 5 | void __assert_fail(const char *assertion, const char *fn, int lineno, const char *func) { 6 | fprintf(stderr, "%s:%d: %s: Assertion `%s` failed\n", fn, lineno, func, assertion); 7 | exit(1); 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/stdio/fclose.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "_file.h" 4 | 5 | int fclose(FILE *fp) { 6 | if (fp == NULL) 7 | return EOF; 8 | return (fp->iof->close)(fp); 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/stdio/fdopen.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "fcntl.h" // O_ACCMODE, etc. 4 | #include "stdlib.h" // calloc 5 | #include "string.h" // strchr 6 | #include "unistd.h" // close 7 | 8 | #include "_file.h" 9 | 10 | #define RCAPA 256 11 | #define WCAPA 128 12 | 13 | static int _fclose(void *cookie) { 14 | FILE *fp = cookie; 15 | _remove_opened_file(fp); 16 | (*fp->flush)(fp); 17 | close(fp->fd); 18 | free(fp); 19 | return 0; 20 | } 21 | 22 | FILE *fdopen(int fd, const char *mode) { 23 | // TODO: Validate fd. 24 | 25 | int flag = 0; 26 | int oflag = _detect_open_flag(mode); 27 | size_t size = sizeof(FILE); 28 | switch (oflag & O_ACCMODE) { 29 | case O_RDONLY: flag |= FF_READ; size += RCAPA; break; 30 | case O_WRONLY: flag |= FF_WRITE; size += WCAPA; break; 31 | case O_RDWR: flag |= FF_READ | FF_WRITE; size += RCAPA + WCAPA; break; 32 | default: break; 33 | } 34 | if (strchr(mode, 'b') != NULL) 35 | flag |= FF_BINARY; 36 | 37 | FILE *fp = calloc(1, size); 38 | if (fp != NULL) { 39 | static const cookie_io_functions_t kIof = { 40 | .read = _fread, 41 | .write = _fwrite, 42 | .seek = _fseek, 43 | .close = _fclose, 44 | }; 45 | 46 | fp->iof = &kIof; 47 | fp->flush = _fflush; 48 | fp->fd = fd; 49 | fp->rp = fp->rs = fp->rcapa = 0; 50 | fp->wp = fp->wcapa = 0; 51 | fp->rbuf = NULL; 52 | fp->wbuf = NULL; 53 | fp->flag = flag; 54 | fp->unget_char = EOF; 55 | 56 | unsigned char *p = (unsigned char*)(fp + 1); 57 | if (flag & FF_READ) { 58 | fp->rbuf = p; 59 | p += (fp->rcapa = RCAPA); 60 | } 61 | if (flag & FF_WRITE) { 62 | fp->wbuf = p; 63 | p += (fp->wcapa = WCAPA); 64 | } 65 | 66 | _add_opened_file(fp); 67 | } 68 | return fp; 69 | } 70 | -------------------------------------------------------------------------------- /libsrc/stdio/feof.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "_file.h" 4 | 5 | int feof(FILE *fp) { 6 | return (fp->flag & FF_EOF) ? 1 : 0; 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/stdio/fflush.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | int fflush(FILE *fp) { 6 | return (fp->flush)(fp); 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/stdio/fgetc.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | int fgetc(FILE *fp) { 6 | int uc = fp->unget_char; 7 | if (uc != EOF) { 8 | fp->unget_char = EOF; 9 | return uc; 10 | } 11 | 12 | unsigned char c; 13 | size_t count = fread(&c, 1, 1, fp); 14 | return count == 1 ? c : EOF; 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/stdio/fgets.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | char *fgets(char *s, int n, FILE *fp) { 4 | --n; 5 | char *p = s; 6 | for (int i = 0; i < n; ++i) { 7 | int c = fgetc(fp); 8 | if (c == EOF) 9 | break; 10 | *p++ = c; 11 | if (c == '\n') 12 | break; 13 | } 14 | if (p == s) 15 | return NULL; 16 | *p = '\0'; 17 | return s; 18 | } 19 | -------------------------------------------------------------------------------- /libsrc/stdio/fileno.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | int fileno(FILE *fp) { 6 | return fp->fd; 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/stdio/fopen.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "fcntl.h" // open 3 | #include "unistd.h" // close 4 | 5 | #include "_file.h" 6 | 7 | FILE *fopen(const char *fileName, const char *mode) { 8 | FILE *fp = NULL; 9 | int flag = _detect_open_flag(mode); 10 | if (flag != -1) { 11 | const int mod = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 12 | int fd = open(fileName, flag, mod); 13 | if (fd >= 0) { 14 | fp = fdopen(fd, mode); 15 | if (fp == NULL) { 16 | close(fd); 17 | } 18 | } 19 | } 20 | return fp; 21 | } 22 | -------------------------------------------------------------------------------- /libsrc/stdio/fprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | int fprintf(FILE *fp, const char *fmt, ...) { 4 | va_list ap; 5 | va_start(ap, fmt); 6 | int len = vfprintf(fp, fmt, ap); 7 | va_end(ap); 8 | return len; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/stdio/fputc.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | // Make sure inline function is emitted. 6 | extern inline int _fputc(int c, FILE *fp); 7 | 8 | int fputc(int c, FILE* fp) { 9 | if (!(fp->flag & FF_WRITE)) 10 | return EOF; 11 | 12 | return _fputc(c, fp); 13 | } 14 | -------------------------------------------------------------------------------- /libsrc/stdio/fputs.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "string.h" 3 | 4 | // Result: Success => positive value, Failure => EOF 5 | int fputs(const char *s, FILE *fp) { 6 | size_t result = fwrite(s, 1, strlen(s), fp); 7 | return result != 0 ? result : EOF; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/stdio/fread.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | size_t fread(void *buffer, size_t size, size_t count, FILE *fp) { 6 | if (!(fp->flag & FF_READ)) 7 | return 0; 8 | ssize_t result = (fp->iof->read)(fp, buffer, size * count); 9 | return result >= 0 ? result / size : 0; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/stdio/fseek.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | int fseek(FILE *fp, long offset, int origin) { 6 | fflush(fp); 7 | off_t o = offset; 8 | if ((fp->iof->seek)(fp, &o, origin) == -1) 9 | return -1; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/stdio/ftell.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "unistd.h" // read 3 | 4 | #include "./_file.h" 5 | 6 | long ftell(FILE *fp) { 7 | off_t result = lseek(fp->fd, 0, SEEK_CUR); 8 | return result >= 0 ? result + fp->wp - (fp->rs - fp->rp) : result; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/stdio/fwrite.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "unistd.h" // write 3 | 4 | #include "./_file.h" 5 | 6 | size_t fwrite(const void *buffer, size_t size, size_t count, FILE *fp) { 7 | if (!(fp->flag & FF_WRITE)) 8 | return 0; 9 | 10 | ssize_t result = (fp->iof->write)(fp, buffer, size * count); 11 | return result >= 0 ? result / size : 0; 12 | } 13 | -------------------------------------------------------------------------------- /libsrc/stdio/getline.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "stdlib.h" // realloc 3 | 4 | ssize_t getline(char **lineptr, size_t *pcapa, FILE *stream) { 5 | const int MIN_CAPA = 16; 6 | ssize_t capa = *pcapa; 7 | ssize_t size = 0; 8 | char *top = *lineptr; 9 | if (top == NULL || capa <= 0) { 10 | top = NULL; 11 | capa = 0; 12 | } 13 | for (;;) { 14 | int c = fgetc(stream); 15 | if (c == EOF) { 16 | if (size == 0) 17 | return -1; 18 | break; 19 | } 20 | 21 | if (size + 1 >= capa) { 22 | ssize_t newcapa = capa * 2; 23 | if (newcapa < MIN_CAPA) 24 | newcapa = MIN_CAPA; 25 | char *reallocated = realloc(top, newcapa); 26 | if (reallocated == NULL) { 27 | *lineptr = top; 28 | *pcapa = capa; 29 | return -1; 30 | } 31 | top = reallocated; 32 | capa = newcapa; 33 | } 34 | 35 | // assert(size < capa); 36 | top[size++] = c; 37 | 38 | if (c == '\n') 39 | break; 40 | } 41 | 42 | // assert(size < capa); 43 | top[size] = '\0'; 44 | *lineptr = top; 45 | *pcapa = capa; 46 | return size; 47 | } 48 | -------------------------------------------------------------------------------- /libsrc/stdio/open_memstream.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "stdlib.h" 4 | #include "_file.h" 5 | 6 | extern void _fmemopen2(void *buf, size_t size, const char *mode, FILE *fp); 7 | 8 | typedef struct MEMFILE { 9 | FILE file; 10 | char **pmem; 11 | size_t *psize; 12 | } MEMFILE; 13 | 14 | static int _memflush2(FILE *fp) { 15 | unsigned int wp = fp->wp; 16 | if (wp < fp->wcapa) { 17 | fp->wbuf[wp] = '\0'; 18 | } 19 | MEMFILE *memfp = (MEMFILE*)fp; 20 | if (memfp->pmem != NULL) 21 | *memfp->pmem = (char*)fp->wbuf; 22 | if (memfp->psize != NULL) 23 | *memfp->psize = wp; 24 | return 0; 25 | } 26 | 27 | FILE *open_memstream(char **ptr, size_t *sizeloc) { 28 | MEMFILE *fp = calloc(1, sizeof(*fp)); 29 | if (fp != NULL) { 30 | _fmemopen2(NULL, 0, "w", &fp->file); 31 | fp->file.flush = _memflush2; 32 | fp->file.flag |= FF_GROWMEM; 33 | fp->pmem = ptr; 34 | fp->psize = sizeloc; 35 | } 36 | return &fp->file; 37 | } 38 | -------------------------------------------------------------------------------- /libsrc/stdio/perror.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "string.h" 3 | #include "errno.h" 4 | 5 | void perror(const char *msg) { 6 | int no = errno; 7 | if (msg != NULL && *msg != '\0') 8 | fprintf(stderr, "%s: ", msg); 9 | fprintf(stderr, "%s\n", strerror(no)); 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/stdio/printf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "stdarg.h" 3 | 4 | int printf(const char *fmt, ...) { 5 | va_list ap; 6 | va_start(ap, fmt); 7 | int len = vfprintf(stdout, fmt, ap); 8 | va_end(ap); 9 | return len; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/stdio/putchar.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #if defined(__GNUC__) 4 | #include "./_file.h" 5 | // gcc replaces `printf("%c", c)` into `putchar(c)` implicitly. 6 | #undef putchar 7 | // Result: Success => c, Failure => EOF 8 | int putchar(int c) { 9 | return _fputc(c, stdout); 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/stdio/puts.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "string.h" 3 | 4 | // Result: Success => positive value, Failure => EOF 5 | int puts(const char *s) { 6 | // gcc replaces `printf("%s\n", s);` into `puts(s)` so fail with infinite loop. 7 | int result = fputs(s, stdout); 8 | if (result >= 0) 9 | result = putchar('\n'); 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/stdio/remove.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "unistd.h" 3 | 4 | int remove(const char *fn) { 5 | return unlink(fn); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/stdio/snprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | int snprintf(char *out, size_t n, const char *fmt, ...) { 4 | va_list ap; 5 | int len; 6 | va_start(ap, fmt); 7 | len = vsnprintf(out, n, fmt, ap); 8 | va_end(ap); 9 | return len; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/stdio/sprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "stdarg.h" 3 | 4 | int sprintf(char *out, const char *fmt, ...) { 5 | va_list ap; 6 | int len; 7 | va_start(ap, fmt); 8 | len = vsnprintf(out, (size_t)-1, fmt, ap); 9 | va_end(ap); 10 | return len; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/stdio/stdin.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "unistd.h" 3 | 4 | #include "_file.h" 5 | #include "_fileman.h" 6 | 7 | #define FFLUSH _fflush 8 | 9 | typedef struct INFILE { 10 | FILE file; 11 | unsigned char rwork[256]; 12 | } INFILE; 13 | 14 | typedef struct OUTFILE { 15 | FILE file; 16 | unsigned char wwork[128]; 17 | } OUTFILE; 18 | 19 | // Same as _fclose, except calling _remove_opend_file and free. 20 | static int _fclose_std(void *cookie) { 21 | FILE *fp = cookie; 22 | // _remove_opened_file(fp); 23 | (*fp->flush)(fp); 24 | close(fp->fd); 25 | // free(fp); 26 | return 0; 27 | } 28 | 29 | static const cookie_io_functions_t kIof = { 30 | .read = _fread, 31 | .write = _fwrite, 32 | .seek = _fseek, 33 | .close = _fclose_std, 34 | }; 35 | #define IOF &kIof 36 | 37 | static INFILE _stdin = {.file={.iof = IOF, .flush = FFLUSH, .fd = STDIN_FILENO, .flag = FF_READ, .rbuf = _stdin.rwork, .rcapa = sizeof(_stdin.rwork), .unget_char=EOF}}; 38 | static OUTFILE _stdout = {.file={.iof = IOF, .flush = FFLUSH, .fd = STDOUT_FILENO, .flag = FF_WRITE, .wbuf = _stdout.wwork, .wcapa = sizeof(_stdout.wwork), .unget_char=EOF}}; 39 | static OUTFILE _stderr = {.file={.iof = IOF, .flush = FFLUSH, .fd = STDERR_FILENO, .flag = FF_WRITE, .wbuf = _stderr.wwork, .wcapa = sizeof(_stderr.wwork), .unget_char=EOF}}; 40 | 41 | #if defined(__riscv) 42 | static struct _reent _impure_entity = { 43 | ._errno = 0, 44 | ._stdin = &_stdin.file, 45 | ._stdout = &_stdout.file, 46 | ._stderr = &_stderr.file, 47 | }; 48 | struct _reent *_impure_ptr = &_impure_entity; 49 | 50 | #else 51 | 52 | FILE *stdin = &_stdin.file; 53 | FILE *stdout = &_stdout.file; 54 | FILE *stderr = &_stderr.file; 55 | #endif 56 | 57 | __attribute__((destructor)) 58 | static void flush_std_files(void) { 59 | FFLUSH(stdout); 60 | FFLUSH(stderr); 61 | } 62 | -------------------------------------------------------------------------------- /libsrc/stdio/tmpfile.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "stdlib.h" // mkstemp 4 | #include "unistd.h" // close 5 | 6 | FILE *tmpfile(void) { 7 | char template[] = "/tmp/tmpXXXXXX"; 8 | int fd = mkstemp(template); 9 | FILE *fp = NULL; 10 | if (fd >= 0) { 11 | unlink(template); 12 | fp = fdopen(fd, "w+"); 13 | if (fp == NULL) { 14 | close(fd); 15 | } 16 | } 17 | return fp; 18 | } 19 | -------------------------------------------------------------------------------- /libsrc/stdio/ungetc.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include "./_file.h" 4 | 5 | int ungetc(int c, FILE *fp) { 6 | if (!(fp->flag & FF_READ)) 7 | return EOF; 8 | fp->unget_char = c; 9 | fp->flag &= ~FF_EOF; 10 | return c; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/stdio/vprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | int vprintf(const char *fmt, va_list ap) { 4 | return vfprintf(stdout, fmt, ap); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdio/vsnprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "unistd.h" 3 | #include "stdarg.h" 4 | 5 | int vsnprintf(char *out, size_t n, const char *fmt, va_list ap) { 6 | int result = 0; 7 | FILE *fp = fmemopen(out, n, "w"); 8 | if (fp != NULL) { 9 | result = vfprintf(fp, fmt, ap); 10 | fclose(fp); 11 | } 12 | return result; 13 | } 14 | -------------------------------------------------------------------------------- /libsrc/stdio/vsprintf.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | int vsprintf(char *buf, const char *fmt, va_list ap) { 4 | return vsnprintf(buf, (size_t)-1, fmt, ap); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/__cxa_atexit.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "_exit.h" 3 | 4 | #define MAX (8) 5 | 6 | typedef struct { 7 | void (*dtor)(void*); 8 | void *arg; 9 | void *dso_handle; 10 | } CxaAtexitBuf; 11 | 12 | static CxaAtexitBuf buf[MAX]; 13 | static int count; 14 | 15 | void *__dso_handle; 16 | 17 | int __cxa_atexit(void (*func)(void*), void *arg, void *d) { 18 | if (count >= MAX) 19 | return 1; 20 | CxaAtexitBuf *p = &buf[count++]; 21 | p->dtor = func; 22 | p->arg = arg; 23 | p->dso_handle = d; 24 | return 0; 25 | } 26 | 27 | static void call_cxa_atexit_funcs(void) { 28 | for (CxaAtexitBuf *p = &buf[count]; p > buf; ) { 29 | --p; 30 | (*p->dtor)(p->arg); 31 | } 32 | } 33 | 34 | __attribute__((constructor)) 35 | static void register_atexit(void) { 36 | static OnExitChain chain = {NULL, call_cxa_atexit_funcs}; 37 | chain.next = __on_exit_chain; 38 | __on_exit_chain = &chain; 39 | } 40 | -------------------------------------------------------------------------------- /libsrc/stdlib/_exit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct OnExitChain { 4 | struct OnExitChain *next; 5 | void (*func)(void); 6 | } OnExitChain; 7 | 8 | extern OnExitChain *__on_exit_chain; 9 | -------------------------------------------------------------------------------- /libsrc/stdlib/_malloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef long Align; 4 | 5 | typedef union header { 6 | struct { 7 | union header *ptr; 8 | unsigned int size; 9 | } s; 10 | Align x; 11 | } Header; 12 | -------------------------------------------------------------------------------- /libsrc/stdlib/_parse_sign.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | 3 | bool _parse_sign(const char **pp) { 4 | const char *p = *pp; 5 | char c = *p; 6 | if (c == '+' || c == '-') 7 | *pp = p + 1; 8 | return c == '-'; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/stdlib/_strtoull_sub.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" // isspace, tolower 2 | 3 | unsigned long long _strtoull_sub(const char *p, char **pp, int base, unsigned long long max) { 4 | char digimax = '0' + (base <= 10 ? base : 10); 5 | char hexmax = 'a' - 10 + base; 6 | unsigned long long premax = max / base; 7 | unsigned long long result = 0; 8 | for (;; ++p) { 9 | char c = *p; 10 | unsigned int n; 11 | if ('0' <= c && c < digimax) 12 | n = c - '0'; 13 | else { 14 | c = tolower(c); 15 | if ('a' <= c && c < hexmax) 16 | n = c - 'a' + 10; 17 | else 18 | break; 19 | } 20 | if (result > premax) { 21 | result = max; 22 | continue; 23 | } 24 | 25 | unsigned long long r = result * base; 26 | unsigned long long d = max - r; 27 | result = n < d ? r + n : max; 28 | } 29 | 30 | if (pp != 0) 31 | *pp = (char*)p; 32 | 33 | return result; 34 | } 35 | -------------------------------------------------------------------------------- /libsrc/stdlib/abs.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | int abs(int x) { 4 | return x >= 0 ? x : -x; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/atexit.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "_exit.h" 3 | 4 | #define MAX (8) 5 | 6 | typedef void (*AtexitFunc)(void); 7 | 8 | static AtexitFunc buf[MAX]; 9 | static int count; 10 | 11 | int atexit(void (*func)(void)) { 12 | if (count >= MAX) 13 | return 1; 14 | buf[count++] = func; 15 | return 0; 16 | } 17 | 18 | static void call_atexit_funcs(void) { 19 | for (AtexitFunc *p = &buf[count]; p > buf; ) { 20 | --p; 21 | (*p)(); 22 | } 23 | } 24 | 25 | __attribute__((constructor)) 26 | static void register_atexit(void) { 27 | static OnExitChain chain = {NULL, call_atexit_funcs}; 28 | chain.next = __on_exit_chain; 29 | __on_exit_chain = &chain; 30 | } 31 | -------------------------------------------------------------------------------- /libsrc/stdlib/atof.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double atof(const char *p) { 5 | return strtod(p, NULL); 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/stdlib/atoi.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "ctype.h" // isspace 3 | #include "stdbool.h" 4 | 5 | int atoi(const char *s) { 6 | for (; isspace(*s); ++s) 7 | ; 8 | 9 | bool negative = false; 10 | char c = *s; 11 | switch (c) { 12 | case '-': 13 | negative = true; 14 | // Fallthrough 15 | case '+': 16 | ++s; 17 | break; 18 | } 19 | 20 | int n = 0; 21 | for (; '0' <= *s && *s <= '9'; ++s) 22 | n = n * 10 + (*s - '0'); 23 | return negative ? -n : n; 24 | } 25 | -------------------------------------------------------------------------------- /libsrc/stdlib/atol.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | long atol(const char *s) { 4 | return strtol(s, NULL, 10); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/atoll.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | long long atoll(const char *s) { 4 | return strtoll(s, NULL, 10); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/bsearch.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, 4 | int (*compare)(const void*, const void*)) { 5 | while (nmemb > 0) { 6 | size_t mid = nmemb >> 1; 7 | char *p = (char*)base + mid * size; 8 | int cmp = compare(key, (void*)p); 9 | if (cmp < 0) { 10 | nmemb = mid; 11 | } else if (cmp > 0) { 12 | base = p + size; 13 | nmemb -= mid + 1; 14 | } else { 15 | return p; 16 | } 17 | } 18 | return NULL; 19 | } 20 | -------------------------------------------------------------------------------- /libsrc/stdlib/calloc.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "string.h" // memset 3 | 4 | void *calloc(size_t nmemb, size_t size) { 5 | size_t nbytes = nmemb * size; 6 | void *adr = malloc(nbytes); 7 | if (adr != NULL) 8 | memset(adr, 0, nbytes); 9 | return adr; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/stdlib/drand48.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double drand48(void) { 5 | return lrand48() * (1.0 / (1UL << 31)); 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/stdlib/environ.c: -------------------------------------------------------------------------------- 1 | #ifndef __APPLE__ 2 | char **environ; 3 | #endif 4 | -------------------------------------------------------------------------------- /libsrc/stdlib/erand48.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #ifndef __NO_FLONUM 4 | double erand48(unsigned short xsubi[3]) { 5 | return nrand48(xsubi) * (1.0 / (1UL << 31)); 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /libsrc/stdlib/exit.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "_exit.h" 3 | 4 | OnExitChain *__on_exit_chain; 5 | 6 | #if defined(__linux__) || defined(__WASM) 7 | #include "stdbool.h" 8 | 9 | #if defined(__WASM) 10 | #include "../_wasm/wasi.h" 11 | #else 12 | #include "../unistd/_syscall.h" 13 | 14 | _Noreturn static void proc_exit(int code); 15 | static void proc_exit(int code) { 16 | #ifdef __NR_exit_group 17 | SYSCALL(__NR_exit_group); 18 | #endif 19 | SYSCALL(__NR_exit); 20 | for (;;) 21 | ; 22 | } 23 | #endif 24 | 25 | void exit(int code) { 26 | // TODO: Guard multiple calls 27 | 28 | OnExitChain *chain = __on_exit_chain; 29 | __on_exit_chain = NULL; 30 | for (; chain != NULL; chain = chain->next) { 31 | chain->func(); 32 | } 33 | 34 | proc_exit(code); 35 | } 36 | 37 | #elif defined(__APPLE__) 38 | 39 | // Use libc. 40 | 41 | extern void exit(int code); 42 | 43 | #else 44 | #error Target not supported 45 | #endif 46 | -------------------------------------------------------------------------------- /libsrc/stdlib/getenv.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "string.h" 3 | 4 | char *getenv(const char *varname) { 5 | #ifdef __APPLE__ 6 | extern char ***_NSGetEnviron(void); 7 | char **environ = *_NSGetEnviron(); 8 | #else 9 | extern char **environ; 10 | #endif 11 | 12 | if (environ != NULL) { 13 | size_t len = strlen(varname); 14 | for (char **pp = environ, *p; (p = *pp++) != NULL;) 15 | if (strncmp(p, varname, len) == 0 && p[len] == '=') 16 | return &p[len + 1]; 17 | } 18 | return NULL; 19 | } 20 | -------------------------------------------------------------------------------- /libsrc/stdlib/getrandom.c: -------------------------------------------------------------------------------- 1 | #include "sys/random.h" 2 | 3 | #if defined(__WASM) 4 | #include "../_wasm/wasi.h" 5 | 6 | ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { 7 | (void)flags; 8 | random_get(buf, buflen); 9 | return buflen; 10 | } 11 | 12 | #else 13 | #include "fcntl.h" // open 14 | #include "unistd.h" // close 15 | 16 | ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { 17 | ssize_t size = 0; 18 | int fd = open(flags & GRND_RANDOM ? "/dev/random" : "/dev/urandom", O_RDONLY); 19 | if (fd != 1) { 20 | size = read(fd, buf, buflen); 21 | close(fd); 22 | } 23 | return size; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/stdlib/labs.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | long labs(long x) { 4 | return x >= 0 ? x : -x; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/llabs.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | long long llabs(long long x) { 4 | return x >= 0 ? x : -x; 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/lrand48.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | // static unsigned short xsubi[3] = {0x2e16, 0xea27, 0x6c4c}; // {1, 0, 0}? 4 | static unsigned short xsubi[3] = {0xdeec, 0x1053, 0x1db2}; 5 | 6 | // [0, 1<<31) 7 | long lrand48(void) { 8 | long val = nrand48(xsubi); 9 | return val; 10 | } 11 | 12 | void srand48(long seedval) { 13 | xsubi[0] = 0x330e; 14 | xsubi[1] = seedval; 15 | xsubi[2] = seedval >> 16; 16 | } 17 | -------------------------------------------------------------------------------- /libsrc/stdlib/malloc.c: -------------------------------------------------------------------------------- 1 | #include "_malloc.h" 2 | #include "stdlib.h" 3 | #include "unistd.h" // for sbrk 4 | 5 | // Memory allocator by Kernighan and Ritchie, 6 | // The C programming Language, 2nd ed. Section 8.7. 7 | 8 | #define PAGESIZE (4096) 9 | 10 | static Header base = {.s={.ptr=&base, .size=0}}; 11 | static Header *freep = &base; 12 | 13 | void free(void *ap) { 14 | Header *bp, *p; 15 | 16 | if (ap == 0) 17 | return; 18 | 19 | bp = (Header*)ap - 1; 20 | for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) 21 | if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) 22 | break; 23 | if (bp + bp->s.size == p->s.ptr) { 24 | bp->s.size += p->s.ptr->s.size; 25 | bp->s.ptr = p->s.ptr->s.ptr; 26 | } else 27 | bp->s.ptr = p->s.ptr; 28 | if (p + p->s.size == bp) { 29 | p->s.size += bp->s.size; 30 | p->s.ptr = bp->s.ptr; 31 | } else 32 | p->s.ptr = bp; 33 | freep = p; 34 | } 35 | 36 | static Header *morecore(size_t nu) { 37 | size_t size; 38 | char *p; 39 | Header *hp; 40 | 41 | size = (nu * sizeof(Header) + (PAGESIZE - 1)) & -PAGESIZE; 42 | p = sbrk(size); 43 | if (p == (char*)-1) 44 | return 0; 45 | hp = (Header*)p; 46 | hp->s.size = size / sizeof(Header); 47 | free((void*)(hp + 1)); 48 | return freep; 49 | } 50 | 51 | void *malloc(size_t nbytes) { 52 | Header *p, *prevp; 53 | size_t nunits; 54 | 55 | nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1; 56 | prevp = freep; 57 | for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) { 58 | if (p->s.size >= nunits) { 59 | if (p->s.size == nunits) 60 | prevp->s.ptr = p->s.ptr; 61 | else { 62 | p->s.size -= nunits; 63 | p += p->s.size; 64 | p->s.size = nunits; 65 | } 66 | freep = prevp; 67 | return (void*)(p + 1); 68 | } 69 | if (p == freep) 70 | if ((p = morecore(nunits)) == 0) 71 | return 0; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /libsrc/stdlib/mkstemp.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | int mkstemp(char *tmpl) { 4 | return mkstemps(tmpl, 0); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/mkstemps.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "errno.h" 3 | #include "fcntl.h" // open 4 | #include "stdbool.h" 5 | #include "stdint.h" // uint32_t 6 | #include "string.h" // strlen 7 | #include "sys/random.h" 8 | 9 | int mkstemps(char *tmpl, int suffixlen) { 10 | #define LETTERS (10 + 26 + 26) 11 | static const char kLetters[LETTERS] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 12 | const int LEN = 6; 13 | const uint32_t RNDMAX = ((1UL << 31) / LETTERS) * LETTERS; 14 | 15 | static bool initialized; 16 | static unsigned short xsubi[3] = {11, 222, 3333}; 17 | if (!initialized) { 18 | initialized = getrandom(xsubi, sizeof(xsubi), 0) == sizeof(xsubi); 19 | } 20 | 21 | size_t len = strlen(tmpl); 22 | if (len < (size_t)(LEN + suffixlen)) { 23 | errno = EINVAL; 24 | return -1; 25 | } 26 | char *p = &tmpl[len - suffixlen - LEN]; 27 | for (int j = 0; j < LEN; ++j) { 28 | if (*p != 'X') { 29 | errno = EINVAL; 30 | return -1; 31 | } 32 | uint32_t r; 33 | do { 34 | r = nrand48(xsubi); 35 | } while (r >= RNDMAX); 36 | *p++ = kLetters[r % LETTERS]; 37 | } 38 | 39 | return open(tmpl, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR); 40 | #undef LETTERS 41 | } 42 | -------------------------------------------------------------------------------- /libsrc/stdlib/nrand48.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #include "stdint.h" // uint64_t 4 | 5 | // [0, 1<<31) 6 | long nrand48(unsigned short xsubi[3]) { 7 | #define A 0x5deece66d 8 | #define C 0x0b 9 | uint64_t x = xsubi[0] | ((uint64_t)xsubi[1] << 16) | ((uint64_t)xsubi[2] << 32); 10 | x = x * A + C; 11 | xsubi[0] = x; 12 | xsubi[1] = x >> 16; 13 | xsubi[2] = x >> 32; 14 | return (long)(x >> (48 - 31)) & ((1L << 31) - 1); 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/stdlib/qsort.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "alloca.h" 3 | #include "string.h" // memcpy 4 | 5 | void qsort(void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *)) { 6 | if (nmemb <= 1) 7 | return; 8 | 9 | char *a = base; 10 | const char *px; 11 | 12 | px = &a[(nmemb >> 1) * size]; 13 | size_t i = 0; 14 | size_t j = nmemb - 1; 15 | char *tmp = alloca(size); 16 | for (;;) { 17 | while (compare(&a[i * size], px) < 0) 18 | ++i; 19 | while (compare(px, &a[j * size]) < 0) 20 | --j; 21 | if (i >= j) 22 | break; 23 | 24 | char *pi = &a[i * size]; 25 | char *pj = &a[j * size]; 26 | memcpy(tmp, pi, size); 27 | memcpy(pi, pj, size); 28 | memcpy(pj, tmp, size); 29 | 30 | if (px == pi) 31 | px = pj; 32 | else if (px == pj) 33 | px = pi; 34 | ++i; 35 | --j; 36 | } 37 | if (i > 1) 38 | qsort(a, i, size, compare); 39 | if (j + 2 < nmemb) 40 | qsort(&a[(j + 1) * size], nmemb - j - 1, size, compare); 41 | } 42 | -------------------------------------------------------------------------------- /libsrc/stdlib/rand.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | int rand(void) { 4 | return lrand48(); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/realloc.c: -------------------------------------------------------------------------------- 1 | #include "_malloc.h" 2 | #include "stdlib.h" 3 | #include "string.h" // memcpy 4 | 5 | void *realloc(void* p, size_t size) { 6 | if (size <= 0) { 7 | free(p); 8 | return NULL; 9 | } 10 | 11 | if (p == NULL) 12 | return malloc(size); 13 | 14 | void* buf = malloc(size); 15 | if (buf != NULL) { 16 | Header* h = (Header*)p - 1; 17 | size_t s = (h->s.size - 1) * sizeof(Header); 18 | memcpy(buf, p, size > s ? s : size); 19 | free(p); 20 | } 21 | return buf; 22 | } 23 | -------------------------------------------------------------------------------- /libsrc/stdlib/srand.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | void srand(unsigned int seed) { 4 | srand48(seed); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/stdlib/strtol.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "ctype.h" // isspace 3 | #include "limits.h" // CHAR_BIT 4 | #include "stdbool.h" 5 | 6 | extern bool _parse_sign(const char **pp); 7 | extern unsigned long long _strtoull_sub(const char *p, char **pp, int base, unsigned long long max); 8 | 9 | long strtol(const char *p, char **pp, int base) { 10 | const char *orig = p; 11 | 12 | for (; isspace(*p); ++p) 13 | ; 14 | 15 | bool neg = _parse_sign(&p); 16 | char *q; 17 | long result; 18 | if (!neg) { 19 | result = (long)_strtoull_sub(p, &q, base, (1ULL << (sizeof(long) * CHAR_BIT - 1)) - 1); 20 | } else { 21 | result = -(long)_strtoull_sub(p, &q, base, 1ULL << (sizeof(long) * CHAR_BIT - 1)); 22 | } 23 | if (pp != 0) 24 | *pp = q == p ? (char*)orig : q; 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /libsrc/stdlib/strtold.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #ifndef __NO_FLONUM 4 | long double strtold(const char* restrict p, char ** restrict pp) { 5 | // TODO: implement. 6 | return strtod(p, pp); 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /libsrc/stdlib/strtoll.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "ctype.h" // isspace 3 | #include "limits.h" // CHAR_BIT 4 | #include "stdbool.h" 5 | 6 | extern bool _parse_sign(const char **pp); 7 | extern unsigned long long _strtoull_sub(const char *p, char **pp, int base, unsigned long long max); 8 | 9 | long long strtoll(const char *p, char **pp, int base) { 10 | const char *orig = p; 11 | 12 | for (; isspace(*p); ++p) 13 | ; 14 | 15 | bool neg = _parse_sign(&p); 16 | char *q; 17 | long long result; 18 | if (!neg) { 19 | result = _strtoull_sub(p, &q, base, (1ULL << (sizeof(long long) * CHAR_BIT - 1)) - 1); 20 | } else { 21 | result = -_strtoull_sub(p, &q, base, 1ULL << (sizeof(long long) * CHAR_BIT - 1)); 22 | } 23 | if (pp != 0) 24 | *pp = q == p ? (char*)orig : q; 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /libsrc/stdlib/strtoul.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | extern unsigned long long _strtoull_sub(const char *p, char **pp, int base, unsigned long long max); 4 | 5 | unsigned long strtoul(const char *p, char **pp, int base) { 6 | const char *orig = p; 7 | if (*p == '+') 8 | ++p; 9 | char *q; 10 | unsigned long result = _strtoull_sub(p, &q, base, -1UL); 11 | if (pp != 0) 12 | *pp = q == p ? (char*)orig : q; 13 | return result; 14 | } 15 | -------------------------------------------------------------------------------- /libsrc/stdlib/strtoull.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "ctype.h" // isspace 3 | 4 | extern unsigned long long _strtoull_sub(const char *p, char **pp, int base, unsigned long long max); 5 | 6 | unsigned long long strtoull(const char *p, char **pp, int base) { 7 | const char *orig = p; 8 | 9 | for (; isspace(*p); ++p) 10 | ; 11 | 12 | if (*p == '+') 13 | ++p; 14 | char *q; 15 | unsigned long long result = _strtoull_sub(p, &q, base, -1ULL); 16 | if (pp != 0) 17 | *pp = q == p ? (char*)orig : q; 18 | return result; 19 | } 20 | -------------------------------------------------------------------------------- /libsrc/string/memccpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void *memccpy(void *dst, const void *src, int c, size_t n) { 4 | char *b = memchr(src, c, n); 5 | if (b != NULL) 6 | n = b - (char *)src; 7 | return memcpy(dst, src, n); 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/memchr.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void *memchr(const void *buf, int c, size_t n) { 4 | for (const char *p = buf, *e = p + n; p < e; ++p) { 5 | if (*p == c) 6 | return (void*)p; 7 | } 8 | return NULL; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/string/memcmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int memcmp(const void *buf1, const void *buf2, size_t n) { 4 | const unsigned char *p = buf1; 5 | const unsigned char *q = buf2; 6 | int d = 0; 7 | for (size_t i = 0; i < n; ++i, ++p, ++q) { 8 | d = (int)*(unsigned char*)p - (int)*(unsigned char*)q; 9 | if (d != 0) 10 | break; 11 | } 12 | return d; 13 | } 14 | -------------------------------------------------------------------------------- /libsrc/string/memcpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void *memcpy(void *dst, const void *src, size_t n) { 4 | #if defined(__WASM) 5 | #define S(x) S_(x) 6 | #define S_(x) #x 7 | #define OP_LOCAL_GET 32 // 0x20 8 | #define OP_0xFC 252 // 0xfc 9 | #define OPFC_MEMORY_COPY 10 // 0x0a 10 | __asm( 11 | S(OP_LOCAL_GET) ",0," // local.get 0 12 | S(OP_LOCAL_GET) ",1," // local.get 1 13 | S(OP_LOCAL_GET) ",2," // local.get 2 14 | S(OP_0xFC) "," S(OPFC_MEMORY_COPY) ",0,0"); // memory.copy 15 | #else 16 | const char *s = src; 17 | char *d = dst; 18 | while (n-- > 0) 19 | *d++ = *s++; 20 | #endif 21 | return dst; 22 | } 23 | -------------------------------------------------------------------------------- /libsrc/string/memmove.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void *memmove(void *dst, const void *src, size_t n) { 4 | #if defined(__WASM) 5 | #define S(x) S_(x) 6 | #define S_(x) #x 7 | #define OP_LOCAL_GET 32 // 0x20 8 | #define OP_0xFC 252 // 0xfc 9 | #define OPFC_MEMORY_COPY 10 // 0x0a 10 | __asm( 11 | S(OP_LOCAL_GET) ",0," // local.get 0 12 | S(OP_LOCAL_GET) ",1," // local.get 1 13 | S(OP_LOCAL_GET) ",2," // local.get 2 14 | S(OP_0xFC) "," S(OPFC_MEMORY_COPY) ",0,0"); // memory.copy 15 | #else 16 | const char *s = src; 17 | char *d = dst; 18 | if (s < d && s + n > d) { 19 | s += n; 20 | d += n; 21 | while (n-- > 0) 22 | *--d = *--s; 23 | } else { 24 | while (n-- > 0) 25 | *d++ = *s++; 26 | } 27 | #endif 28 | return dst; 29 | } 30 | -------------------------------------------------------------------------------- /libsrc/string/memset.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void *memset(void *buf, int val, size_t size) { 4 | #if defined(__WASM) 5 | #define S(x) S_(x) 6 | #define S_(x) #x 7 | #define OP_LOCAL_GET 32 // 0x20 8 | #define OP_0xFC 252 // 0xfc 9 | #define OPFC_MEMORY_FILL 11 // 0x0b 10 | __asm( 11 | S(OP_LOCAL_GET) ",0," // local.get 0 12 | S(OP_LOCAL_GET) ",1," // local.get 1 13 | S(OP_LOCAL_GET) ",2," // local.get 2 14 | S(OP_0xFC) "," S(OPFC_MEMORY_FILL) ",0"); // memory.fill 15 | #else 16 | unsigned char *p = buf; 17 | unsigned char v = val; 18 | for (size_t i = 0; i < size; ++i) 19 | *p++ = v; 20 | #endif 21 | return buf; 22 | } 23 | -------------------------------------------------------------------------------- /libsrc/string/stpcpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *stpcpy(char *dst, const char *src) { 4 | while ((*dst++ = *src++) != '\0') 5 | ; 6 | return dst; 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/string/stpncpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *stpncpy(char *dst, const char *src, size_t n) { 4 | for (; n > 0 && (*dst++ = *src++) != '\0'; --n) 5 | ; 6 | return dst; 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/string/strcasecmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "ctype.h" // tolower 3 | 4 | int strcasecmp(const char *p, const char *q) { 5 | for (;; ++p, ++q) { 6 | unsigned char c1 = *(unsigned char*)p; 7 | unsigned char c2 = *(unsigned char*)q; 8 | int d = (int)c1 - (int)c2; 9 | if (d != 0) 10 | return d; 11 | if (c1 == 0) 12 | break; 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/string/strcat.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strcat(char *dst, const char *src) { 4 | strcpy(dst + strlen(dst), src); 5 | return dst; 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/string/strchr.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strchr(const char *s, int c) { 4 | for (;; ++s) { 5 | if (*s == c) 6 | return (char*)s; 7 | if (*s == '\0') 8 | return NULL; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/string/strcmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int strcmp(const char *p, const char *q) { 4 | while (*p != '\0' && *p == *q) { 5 | ++p; 6 | ++q; 7 | } 8 | return (int)*(unsigned char*)p - (int)*(unsigned char*)q; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/string/strcoll.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int strcoll(const char *p, const char *q) { 4 | return strcmp(p, q); 5 | } 6 | -------------------------------------------------------------------------------- /libsrc/string/strcpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strcpy(char *dst, const char *src) { 4 | char *os = dst; 5 | while ((*dst++ = *src++) != '\0') 6 | ; 7 | return os; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strcspn.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t strcspn(const char *s, const char *reject) { 4 | size_t n; 5 | for (n = 0; s[n] != '\0' && strchr(reject, s[n]) == NULL; ++n) 6 | ; 7 | return n; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strdup.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "stdlib.h" // malloc 3 | 4 | char *strdup(const char *str) { 5 | return strndup(str, strlen(str)); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/string/strerror.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | static char *strerrors[] = { 4 | "Success", 5 | "Operation not permitted", 6 | "No such file or directory", 7 | "No such process", 8 | "Interrupted system call", 9 | "I/O error", 10 | "No such device or address", 11 | "Argument list too long", 12 | "Exec format error", 13 | "Bad file number", 14 | "No child processes", 15 | "Try again", 16 | "Out of memory", 17 | "Permission denied", 18 | "Bad address", 19 | "Block device required", 20 | "Device or resource busy", 21 | "File exists", 22 | "Cross-device link", 23 | "No such device", 24 | "Not a directory", 25 | "Is a directory", 26 | "Invalid argument", 27 | "File table overflow", 28 | "Too many open files", 29 | "Not a typewriter", 30 | "Text file busy", 31 | "File too large", 32 | "No space left on device", 33 | "Illegal seek", 34 | "Read-only file system", 35 | "Too many links", 36 | "Broken pipe", 37 | "Math argument out of domain of func", 38 | "Math result not representable", 39 | }; 40 | 41 | char *strerror(int no) { 42 | if ((unsigned int)no >= (unsigned int)(sizeof(strerrors) / sizeof(*strerrors))) 43 | return "Unknown error"; 44 | return strerrors[no]; 45 | } 46 | -------------------------------------------------------------------------------- /libsrc/string/strerror_r.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int strerror_r(int no, char *dst, size_t n) { 4 | strncpy(dst, strerror(no), n); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/string/strlen.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t strlen(const char *s) { 4 | const char *p; 5 | for (p = s; *p != '\0'; ++p) 6 | ; 7 | return p - s; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strncasecmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "ctype.h" // tolower 3 | 4 | int strncasecmp(const char *p, const char *q, size_t n) { 5 | for (; n > 0; --n, ++p, ++q) { 6 | int c1 = tolower(*(unsigned char*)p); 7 | int c2 = tolower(*(unsigned char*)q); 8 | int d = c1 - c2; 9 | if (d != 0) 10 | return d; 11 | if (c1 == 0) 12 | break; 13 | } 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /libsrc/string/strncat.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strncat(char *dst, const char *src, size_t n) { 4 | char *os = dst; 5 | dst += strlen(dst); 6 | for (; n > 0 && *src != '\0'; --n) 7 | *dst++ = *src++; 8 | *dst = '\0'; 9 | return os; 10 | } 11 | -------------------------------------------------------------------------------- /libsrc/string/strncmp.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | int strncmp(const char *p, const char *q, size_t n) { 4 | while (n > 0 && *p == *q && *p != '\0') 5 | n--, p++, q++; 6 | return n == 0 ? 0 : (int)*(unsigned char*)p - (int)*(unsigned char*)q; 7 | } 8 | -------------------------------------------------------------------------------- /libsrc/string/strncpy.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strncpy(char *dst, const char *src, size_t n) { 4 | char *os = dst; 5 | for (; n > 0 && (*dst++ = *src++) != '\0'; --n) 6 | ; 7 | return os; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strndup.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "stdlib.h" // malloc 3 | 4 | char *strndup(const char *str, size_t size) { 5 | char *dup = malloc(size + 1); 6 | if (dup != NULL) { 7 | memcpy(dup, str, size); 8 | dup[size] = '\0'; 9 | } 10 | return dup; 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/string/strnlen.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t strnlen(const char *s, size_t n) { 4 | size_t len; 5 | for (len = 0; len < n && s[len] != '\0'; ++len) 6 | ; 7 | return len; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strpbrk.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strpbrk(const char *s, const char *accept) { 4 | const char *r = s + strcspn(s, accept); 5 | if (*r == '\0') 6 | return NULL; 7 | return (char *)r; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strrchr.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strrchr(const char *s, int c) { 4 | char *last = NULL; 5 | for (;; ++s) { 6 | if (*s == c) 7 | last = (char*)s; 8 | if (*s == '\0') 9 | return last; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /libsrc/string/strspn.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t strspn(const char *s, const char *accept) { 4 | size_t n; 5 | for (n = 0; s[n] != '\0' && strchr(accept, s[n]) != NULL; ++n) 6 | ; 7 | return n; 8 | } 9 | -------------------------------------------------------------------------------- /libsrc/string/strstr.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strstr(const char *s1, const char *s2) { 4 | for (size_t len = strlen(s2); *s1 != '\0'; ++s1) { 5 | if (strncmp(s1, s2, len) == 0) 6 | return (char*)s1; 7 | } 8 | return NULL; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/string/strtok.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strtok(char *src, const char *delim) { 4 | static char *ptr; 5 | return strtok_r(src, delim, &ptr); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/string/strtok_r.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | char *strtok_r(char *src, const char *delim, char **ptr) { 4 | if (src != NULL) 5 | *ptr = src; 6 | *ptr += strspn(*ptr, delim); 7 | if (**ptr == '\0') 8 | return NULL; 9 | char *r = *ptr; 10 | size_t n = strcspn(r, delim); 11 | r[n] = '\0'; 12 | *ptr += n + 1; 13 | return r; 14 | } 15 | -------------------------------------------------------------------------------- /libsrc/tests/longjmp_test.c: -------------------------------------------------------------------------------- 1 | // Longjmp test 2 | // 3 | // Compile: 4 | // $ ./xcc -olongjmp_test libsrc/tests/longjmp_test.c 5 | // 6 | // Run: 7 | // $ ./longjmp_test || echo fail 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "../../tests/xtest.h" 15 | 16 | jmp_buf env; 17 | 18 | static void simple(int param) { 19 | if (param) 20 | longjmp(env, param * 2); 21 | } 22 | TEST(simple) { 23 | int result; 24 | result = setjmp(env); 25 | if (result == 0) { 26 | simple(0); 27 | } else { 28 | fail("unreachable1"); 29 | } 30 | 31 | if ((result = setjmp(env)) == 0) { 32 | simple(255); 33 | fail("unreachable2"); 34 | } else { 35 | EXPECT_EQ(510, result); 36 | } 37 | 38 | result = 0; 39 | if (setjmp(env) == 0) { 40 | simple(1); 41 | } else { 42 | result = 4321; 43 | } 44 | EXPECT_EQ(4321, result); 45 | } 46 | 47 | TEST(zero) { 48 | int result = setjmp(env); 49 | if (result == 0) { 50 | longjmp(env, 0); 51 | } 52 | EXPECT_TRUE(result != 0); 53 | } 54 | 55 | TEST(multiple_times) { 56 | int result; 57 | static int i; // Local variable might be roll back! 58 | i = 0; 59 | if (result = setjmp(env), result == 0) { 60 | simple(1); 61 | fail("unreachable"); 62 | } else { 63 | if (++i < 5) 64 | simple(result); 65 | EXPECT_EQ(32, result); 66 | } 67 | } 68 | 69 | static void nested(jmp_buf env2) { 70 | if (!setjmp(env)) 71 | longjmp(env2, 777); 72 | } 73 | TEST(nested) { 74 | jmp_buf env2; 75 | int result; 76 | if (result = setjmp(env2), result) { 77 | EXPECT_EQ(777, result); 78 | } else { 79 | nested(env2); 80 | fail("nested, unreachable"); 81 | } 82 | } 83 | 84 | TEST(volatile_local_preserved) { 85 | volatile int x = 0; 86 | int result = setjmp(env); 87 | if (result == 0) { 88 | x = 99; 89 | longjmp(env, 1); 90 | } 91 | EXPECT_EQ(99, x); 92 | } 93 | 94 | TEST(sideeffect) { 95 | jmp_buf envs[2]; 96 | memset(&envs[1], -1, sizeof(envs[1])); 97 | int result = -1; 98 | volatile int i = 1; 99 | if (setjmp(envs[i--]) == 0) { 100 | jmp_buf *p = &envs[0]; 101 | volatile int val; 102 | val = 55; 103 | if ((result = setjmp(envs[0])) == 0) { 104 | longjmp(*p++, ++val); 105 | } 106 | } 107 | EXPECT_EQ(56, result); 108 | EXPECT_EQ(0, i); 109 | } 110 | 111 | XTEST_MAIN(); 112 | -------------------------------------------------------------------------------- /libsrc/unistd/brk.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "stdio.h" // EOF 3 | 4 | #if defined(__linux__) 5 | #include "_syscall.h" 6 | 7 | static void *_brk(void *addr) { 8 | void *ret; 9 | SYSCALL_RET(__NR_brk, ret); 10 | return ret; 11 | } 12 | #elif defined(__APPLE__) 13 | extern void *_brk(void *addr); 14 | #endif 15 | 16 | static char *curbrk; 17 | #define CURBRK curbrk 18 | 19 | int brk(void *addr) { 20 | void *result = _brk(addr); 21 | curbrk = result; 22 | return result < addr ? EOF : 0; 23 | } 24 | 25 | void *sbrk(intptr_t increment) { 26 | char *p = CURBRK; 27 | if (p == NULL) { 28 | if (brk(NULL) < 0) 29 | return (void*)-1; 30 | p = CURBRK; 31 | } 32 | char *next = p + increment; 33 | if (brk(next) < 0) 34 | return (void*)-1; 35 | return p; 36 | } 37 | -------------------------------------------------------------------------------- /libsrc/unistd/chdir.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | int chdir(const char *path) { 5 | int ret; 6 | SYSCALL_RET(__NR_chdir, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/chmod.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" // mode_t 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_chmod) 5 | int chmod(const char *pathname, mode_t mode) { 6 | int ret; 7 | SYSCALL_RET(__NR_chmod, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | 12 | #elif defined(__NR_fchmodat) 13 | #include "fcntl.h" // AT_FDCWD 14 | 15 | int chmod(const char *pathname, mode_t mode) { 16 | return fchmodat(AT_FDCWD, pathname, mode, 0); 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /libsrc/unistd/clock_gettime.c: -------------------------------------------------------------------------------- 1 | #include "time.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_clock_gettime) 5 | int clock_gettime(clockid_t clk_id, struct timespec *tp) { 6 | int ret; 7 | SYSCALL_RET(__NR_clock_gettime, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/clone3.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_clone3) 5 | #include "stdint.h" 6 | 7 | long clone3(struct clone_args *cl_args, size_t size) { 8 | long ret; 9 | SYSCALL_RET(__NR_clone3, ret); 10 | SET_ERRNO(ret); 11 | return ret; 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /libsrc/unistd/close.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | int close(int fd) { 5 | int ret; 6 | SYSCALL_RET(__NR_close, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/dup.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | int dup(int fd) { 5 | int ret; 6 | SYSCALL_RET(__NR_dup, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/execve.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | int execve(const char *path, char *const args[], char *const envp[]) { 5 | int ret; 6 | SYSCALL_RET(__NR_execve, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/execvp.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | 3 | int execvp(const char *path, char *const args[]) { 4 | #ifdef __APPLE__ 5 | extern char ***_NSGetEnviron(void); 6 | char **environ = *_NSGetEnviron(); 7 | #else 8 | extern char **environ; 9 | #endif 10 | 11 | return execve(path, args, environ); 12 | } 13 | -------------------------------------------------------------------------------- /libsrc/unistd/fchmodat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" // mode_t 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_fchmodat) 5 | int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags) { 6 | int ret; 7 | #if defined(__x86_64__) 8 | SYSCALL_ARGCOUNT(4); 9 | #endif 10 | SYSCALL_RET(__NR_fchmodat, ret); 11 | SET_ERRNO(ret); 12 | return ret; 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /libsrc/unistd/fork.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_fork) 5 | pid_t fork(void) { 6 | pid_t ret; 7 | SYSCALL_RET(__NR_fork, ret); 8 | return ret; 9 | } 10 | 11 | #elif defined(__NR_clone3) 12 | #include "signal.h" 13 | 14 | pid_t fork(void) { 15 | struct clone_args cl_args = { 16 | .exit_signal = SIGCHLD, 17 | }; 18 | return clone3(&cl_args, sizeof(cl_args)); 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /libsrc/unistd/fstat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_fstat) 5 | int fstat(int fd, struct stat *buf) { 6 | int ret; 7 | SYSCALL_RET(__NR_fstat, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/fstatat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_fstatat) 5 | int fstatat(int fd, const char *pathname, struct stat *buf, int flag) { 6 | int ret; 7 | #if defined(__x86_64__) 8 | SYSCALL_ARGCOUNT(4); 9 | #endif 10 | SYSCALL_RET(__NR_fstatat, ret); 11 | SET_ERRNO(ret); 12 | return ret; 13 | } 14 | 15 | #elif defined(__NR_newfstatat) 16 | int fstatat(int fd, const char *pathname, struct stat *buf, int flag) { 17 | int ret; 18 | #if defined(__x86_64__) 19 | SYSCALL_ARGCOUNT(4); 20 | #endif 21 | SYSCALL_RET(__NR_newfstatat, ret); 22 | SET_ERRNO(ret); 23 | return ret; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /libsrc/unistd/getcwd.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "errno.h" 3 | #include "stdlib.h" // malloc 4 | 5 | #if defined(__APPLE__) 6 | extern int _getcwd(char *, size_t); 7 | 8 | #elif defined(__linux__) 9 | #include "_syscall.h" 10 | 11 | static int _getcwd(char *buffer, size_t size) { 12 | int ret; 13 | SYSCALL_RET(__NR_getcwd, ret); 14 | SET_ERRNO(ret); 15 | return ret; 16 | } 17 | #endif 18 | 19 | char *getcwd(char *buffer, size_t size) { 20 | void *allocated = NULL; 21 | if (buffer == NULL) { 22 | if (size == 0) { 23 | size = 512; // PATH_MAX 24 | } 25 | buffer = allocated = malloc(size + 1); 26 | if (buffer == NULL) 27 | return NULL; 28 | } 29 | int result = _getcwd(buffer, size); 30 | if (result < 0) { 31 | errno = -result; 32 | free(allocated); 33 | return NULL; 34 | } 35 | return buffer; 36 | } 37 | -------------------------------------------------------------------------------- /libsrc/unistd/ioctl.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_ioctl) 5 | int ioctl(int fd, int request, ...) { 6 | int ret; 7 | SYSCALL_RET(__NR_ioctl, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/isatty.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "sys/ioctl.h" // termio 3 | 4 | int isatty(int fd) { 5 | #if defined(__NR_ioctl) 6 | struct termio tm; 7 | return ioctl(fd, TCGETA, &tm) == 0 ? 1 : 0; 8 | #else 9 | // TODO: 10 | return fd < 3; 11 | #endif 12 | } 13 | -------------------------------------------------------------------------------- /libsrc/unistd/kill.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | int kill(pid_t pid, int sig) { 5 | int ret; 6 | SYSCALL_RET(__NR_kill, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/lseek.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | off_t lseek(int fd, off_t offset, int whence) { 5 | off_t ret; 6 | SYSCALL_RET(__NR_lseek, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/lstat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_lstat) 5 | int lstat(const char *pathname, struct stat *buf) { 6 | int ret; 7 | SYSCALL_RET(__NR_lstat, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #elif defined(__NR_newfstatat) 12 | #include "fcntl.h" // AT_FDCWD 13 | int lstat(const char *pathname, struct stat *buf) { 14 | return fstatat(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW); 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /libsrc/unistd/mkdir.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_mkdir) 5 | int mkdir(const char *pathname, mode_t mode) { 6 | int ret; 7 | SYSCALL_RET(__NR_mkdir, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | 12 | #elif defined(__NR_mkdirat) 13 | #include "fcntl.h" 14 | 15 | int mkdir(const char *pathname, mode_t mode) { 16 | return mkdirat(AT_FDCWD, pathname, mode); 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /libsrc/unistd/mkdirat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_mkdirat) 5 | int mkdirat(int dirfd, const char *pathname, mode_t mode) { 6 | int ret; 7 | SYSCALL_RET(__NR_mkdirat, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/open.c: -------------------------------------------------------------------------------- 1 | // #include "fcntl.h" // Avoid conflicting with prototype definition. 2 | #include "sys/stat.h" // mode_t 3 | #include "_syscall.h" 4 | 5 | #if defined(__NR_open) 6 | int open(const char *fn, int flag, mode_t mode) { 7 | int ret; 8 | SYSCALL_RET(__NR_open, ret); 9 | SET_ERRNO(ret); 10 | return ret; 11 | } 12 | #elif defined(__NR_openat) 13 | 14 | // #include "fcntl.h" // AT_FDCWD 15 | #define AT_FDCWD -100 // Avoid conflicting with prototype definition. 16 | 17 | int open(const char *fn, int flag, mode_t mode) { 18 | extern int openat(int dirfd, const char *fn, int flag, mode_t mode); 19 | return openat(AT_FDCWD, fn, flag, mode); 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /libsrc/unistd/openat.c: -------------------------------------------------------------------------------- 1 | // #include "fcntl.h" // Avoid conflicting with prototype definition. 2 | // #include "unistd.h" 3 | #include "sys/stat.h" // mode_t 4 | #include "_syscall.h" 5 | 6 | #if defined(__NR_openat) 7 | int openat(int dirfd, const char *fn, int flag, mode_t mode) { 8 | int ret; 9 | #if defined(__x86_64__) 10 | SYSCALL_ARGCOUNT(4); 11 | #endif 12 | SYSCALL_RET(__NR_openat, ret); 13 | SET_ERRNO(ret); 14 | return ret; 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /libsrc/unistd/pipe.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_pipe) 5 | int pipe(int *pipefd) { 6 | int ret; 7 | SYSCALL_RET(__NR_pipe, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #elif defined(__NR_pipe2) 12 | int pipe(int *pipefd) { 13 | return pipe2(pipefd, 0); 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /libsrc/unistd/pipe2.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_pipe2) 5 | int pipe2(int *pipefd, int flag) { 6 | int ret; 7 | SYSCALL_RET(__NR_pipe2, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/read.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | ssize_t read(int fd, void *buf, size_t size) { 5 | ssize_t ret; 6 | SYSCALL_RET(__NR_read, ret); 7 | SET_ERRNO(ret); 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /libsrc/unistd/rmdir.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_rmdir) 5 | int rmdir(const char *pathname) { 6 | int ret; 7 | SYSCALL_RET(__NR_rmdir, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | 12 | #elif defined(__NR_unlinkat) 13 | #include "unistd.h" 14 | #include "fcntl.h" 15 | 16 | int rmdir(const char *pathname) { 17 | return unlinkat(AT_FDCWD, pathname, AT_REMOVEDIR); 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /libsrc/unistd/stat.c: -------------------------------------------------------------------------------- 1 | #include "sys/stat.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_stat) 5 | int stat(const char *pathname, struct stat *buf) { 6 | int ret; 7 | SYSCALL_RET(__NR_stat, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #elif defined(__NR_fstatat) || defined(__NR_newfstatat) 12 | #include "fcntl.h" // AT_FDCWD 13 | int stat(const char *pathname, struct stat *buf) { 14 | return fstatat(AT_FDCWD, pathname, buf, 0); 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /libsrc/unistd/time.c: -------------------------------------------------------------------------------- 1 | #include "time.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_time) 5 | time_t time(time_t *timer) { 6 | time_t ret; 7 | SYSCALL_RET(__NR_time, ret); 8 | return ret; 9 | } 10 | 11 | #elif defined(__NR_clock_gettime) 12 | #include "stddef.h" // NULL 13 | 14 | time_t time(time_t *timer) { 15 | struct timespec ts; 16 | clock_gettime(CLOCK_REALTIME, &ts); 17 | if (timer != NULL) 18 | *timer = ts.tv_sec; 19 | return ts.tv_sec; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /libsrc/unistd/unlink.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_unlink) 5 | int unlink(const char *pathname) { 6 | int ret; 7 | SYSCALL_RET(__NR_unlink, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | 12 | #elif defined(__NR_unlinkat) 13 | #include "fcntl.h" // AT_FDCWD 14 | int unlink(const char *pathname) { 15 | return unlinkat(AT_FDCWD, pathname, 0); 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /libsrc/unistd/unlinkat.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | #include "_syscall.h" 3 | 4 | #if defined(__NR_unlinkat) 5 | int unlinkat(int dirfd, const char *pathname, int flags) { 6 | int ret; 7 | SYSCALL_RET(__NR_unlinkat, ret); 8 | SET_ERRNO(ret); 9 | return ret; 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /libsrc/unistd/wait.c: -------------------------------------------------------------------------------- 1 | #include "sys/wait.h" 2 | #include "stddef.h" // NULL 3 | 4 | pid_t wait(int *status) { 5 | return wait4(-1, status, 0, NULL); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/unistd/wait4.c: -------------------------------------------------------------------------------- 1 | #if !defined(__APPLE__) 2 | #include "sys/wait.h" 3 | #include "_syscall.h" 4 | #include "errno.h" 5 | 6 | pid_t wait4(pid_t pid, int* status, int options, struct rusage *usage) { 7 | int ret; 8 | #if defined(__x86_64__) 9 | SYSCALL_ARGCOUNT(4); 10 | #endif 11 | SYSCALL_RET(__NR_wait4, ret); 12 | SET_ERRNO(ret); 13 | return ret; 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /libsrc/unistd/waitpid.c: -------------------------------------------------------------------------------- 1 | #include "sys/wait.h" 2 | #include "stddef.h" // NULL 3 | 4 | pid_t waitpid(pid_t pid, int *status, int options) { 5 | return wait4(pid, status, options, NULL); 6 | } 7 | -------------------------------------------------------------------------------- /libsrc/unistd/write.c: -------------------------------------------------------------------------------- 1 | #include "unistd.h" 2 | 3 | #if defined(__linux__) 4 | #include "_syscall.h" 5 | 6 | ssize_t write(int fd, const void *str, size_t len) { 7 | ssize_t ret; 8 | SYSCALL_RET(__NR_write, ret); 9 | return ret; 10 | } 11 | 12 | #elif defined(__APPLE__) 13 | 14 | // Use libc. 15 | #define USE_LIBC 16 | 17 | #else 18 | #error Target not supported 19 | #endif 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wcc", 3 | "version": "0.1.0", 4 | "description": "C-compiler for wasm", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm run default", 8 | "default": "npm run build-assets && npx vite --port=3000", 9 | "build-assets": "make assets", 10 | "lint": "eslint src/wcc/www/**/*.ts", 11 | "lint:fix": "eslint --fix src/wcc/www/**/*.ts", 12 | "release": "npx vite build", 13 | "clean": "rm -rf public release" 14 | }, 15 | "author": "tyfkda", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/tyfkda/xcc" 19 | }, 20 | "license": "MIT", 21 | "engines": { 22 | "node": ">=20.0" 23 | }, 24 | "devDependencies": { 25 | "@types/alpinejs": "~3.13.11", 26 | "@types/node": "~22.14.1", 27 | "@types/path-browserify": "~1.0.3", 28 | "@typescript-eslint/eslint-plugin": "~8.30.1", 29 | "@typescript-eslint/parser": "~8.30.1", 30 | "commander": "~13.1.0", 31 | "sass": "~1.86.3", 32 | "ts-node": "~10.9.2", 33 | "vite": "~6.3.1" 34 | }, 35 | "dependencies": { 36 | "@wasmer/wasi": "~0.12.0", 37 | "@wasmer/wasmfs": "~0.12.0", 38 | "alpinejs": "~3.14.9", 39 | "buffer": "~6.0.3", 40 | "core-js": "~3.41.0", 41 | "fflate": "~0.8.2", 42 | "path-browserify": "~1.0.1", 43 | "split.js": "~1.6.5" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/_debug/dump_type.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ast.h" 5 | #include "fe_misc.h" 6 | #include "lexer.h" 7 | #include "parser.h" 8 | #include "table.h" 9 | #include "type.h" 10 | #include "var.h" 11 | 12 | int main(int argc, char *argv[]) { 13 | if (argc < 2) { 14 | fprintf(stderr, "dump_type: type...\n"); 15 | return 1; 16 | } 17 | 18 | init_lexer(); 19 | 20 | Scope *scope = new_scope(global_scope); 21 | curscope = scope; 22 | 23 | for (int i = 1; i < argc; ++i) { 24 | char *source = argv[i]; 25 | set_source_string(source, "*type*", 1); 26 | 27 | int storage; 28 | Token *ident; 29 | const Type *type = parse_var_def(NULL, &storage, &ident); 30 | 31 | FILE *fp = stdout; 32 | print_type(fp, type); 33 | if (ident != NULL) { 34 | fprintf(fp, " %.*s", NAMES(ident->ident)); 35 | } 36 | fputs("\n", fp); 37 | } 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/as/arch/aarch64/inst.h: -------------------------------------------------------------------------------- 1 | // aarch64 Instruction 2 | 3 | #pragma once 4 | 5 | #include // int64_t 6 | 7 | typedef struct Expr Expr; 8 | 9 | enum Opcode { 10 | NOOP, 11 | MOV, MOVK, 12 | ADD_R, ADD_I, SUB_R, SUB_I, 13 | MUL, SDIV, UDIV, 14 | MADD, MSUB, 15 | AND, ORR, EOR, EON, 16 | CMP_R, CMP_I, CMN_R, CMN_I, 17 | LSL_R, LSL_I, 18 | LSR_R, LSR_I, 19 | ASR_R, ASR_I, 20 | SXTB, SXTH, SXTW, 21 | UXTB, UXTH, UXTW, 22 | LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW, 23 | STRB, STRH, STR, 24 | LDP, STP, 25 | ADRP, 26 | CSET, 27 | B, BR, 28 | BEQ, BNE, BHS, BLO, BMI, BPL, BVS, BVC, 29 | BHI, BLS, BGE, BLT, BGT, BLE, BAL, BNV, 30 | BL, BLR, 31 | RET, 32 | SVC, 33 | 34 | F_LDR, F_STR, 35 | F_LDP, F_STP, 36 | FMOV, 37 | FADD, FSUB, FMUL, FDIV, 38 | FCMP, FNEG, 39 | FSQRT, 40 | SCVTF, UCVTF, 41 | FCVT, FCVTZS, FCVTZU, 42 | }; 43 | 44 | enum RegSize { 45 | REG32, 46 | REG64, 47 | }; 48 | 49 | typedef struct { 50 | char size; // RegSize 51 | char no; // 0~31 52 | char sp; 53 | } Reg; 54 | 55 | enum CondType { 56 | NOCOND = -1, 57 | EQ, NE, HS, LO, MI, PL, VS, VC, 58 | HI, LS, GE, LT, GT, LE, AL, NV, 59 | }; 60 | 61 | enum OperandType { 62 | NOOPERAND, 63 | REG, // reg 64 | IMMEDIATE, // 1234 65 | DIRECT, // foobar + 345 66 | INDIRECT, // indirect: [reg,#nn] 67 | // pre-index: [reg,#nn]! 68 | // post-index: [reg],#nn 69 | REGISTER_OFFSET, // [reg,reg,#nn] 70 | COND, 71 | SHIFT, 72 | EXTEND, 73 | FREG, // freg 74 | }; 75 | 76 | #define LF_PAGE (1 << 0) 77 | #define LF_PAGEOFF (1 << 1) 78 | #define LF_GOT (1 << 2) 79 | 80 | typedef struct { 81 | Expr *expr; 82 | int flag; 83 | } ExprWithFlag; 84 | 85 | typedef struct Operand { 86 | enum OperandType type; 87 | union { 88 | Reg reg; 89 | int64_t immediate; 90 | struct { 91 | ExprWithFlag expr; 92 | } direct; 93 | struct { 94 | ExprWithFlag offset; 95 | Reg reg; 96 | int prepost; // 0=none, 1=pre, 2=post 97 | } indirect; 98 | struct { 99 | Expr *scale; 100 | Reg base_reg; 101 | Reg index_reg; 102 | int extend; // 0=no, 1=sxtw, 2=uxtw, 3=lsl, 4=sxtx 103 | } register_offset; 104 | enum CondType cond; 105 | struct { 106 | int option; 107 | int imm; 108 | } extend; 109 | }; 110 | } Operand; 111 | 112 | typedef struct Inst { 113 | enum Opcode op; 114 | Operand opr[4]; 115 | } Inst; 116 | -------------------------------------------------------------------------------- /src/as/arch/riscv64/inst.h: -------------------------------------------------------------------------------- 1 | // riscv64 Instruction 2 | 3 | #pragma once 4 | 5 | #include // int64_t 6 | 7 | typedef struct Expr Expr; 8 | 9 | // Must match the order with kOpTable in parse_riscv64.c 10 | enum Opcode { 11 | NOOP, 12 | MV, 13 | LI, 14 | LA, 15 | ADD, ADDW, 16 | ADDI, ADDIW, 17 | SUB, SUBW, 18 | MUL, MULW, 19 | DIV, DIVU, DIVW, DIVUW, 20 | REM, REMU, REMW, REMUW, 21 | AND, ANDI, 22 | OR, ORI, 23 | XOR, XORI, 24 | NEG, 25 | NOT, 26 | SEXT_B, SEXT_H, SEXT_W, 27 | ZEXT_B, ZEXT_H, ZEXT_W, 28 | SLL, SLLW, SLLI, SLLIW, 29 | SRL, SRLW, SRLI, SRLIW, 30 | SRA, SRAW, SRAI, SRAIW, 31 | LB, LH, LW, LD, 32 | LBU, LHU, LWU, 33 | SB, SH, SW, SD, 34 | SLT, SLTU, SLTI, SLTIU, 35 | SEQZ, SNEZ, SLTZ, SGTZ, 36 | J, 37 | JR, 38 | JALR, 39 | BEQ, BNE, BLT, BGE, BLTU, BGEU, 40 | CALL, 41 | RET, 42 | ECALL, 43 | 44 | FADD_D, FSUB_D, FMUL_D, FDIV_D, 45 | FADD_S, FSUB_S, FMUL_S, FDIV_S, 46 | FSQRT_D, FSQRT_S, 47 | FSGNJ_D, FSGNJN_D, FSGNJX_D, 48 | FSGNJ_S, FSGNJN_S, FSGNJX_S, 49 | FMV_D, FNEG_D, 50 | FMV_S, FNEG_S, 51 | FMV_X_D, FMV_X_W, 52 | FEQ_D, FLT_D, FLE_D, 53 | FEQ_S, FLT_S, FLE_S, 54 | FLD, FLW, FSD, FSW, 55 | 56 | FCVT_D_W, FCVT_D_WU, FCVT_D_L, FCVT_D_LU, 57 | FCVT_W_D, FCVT_WU_D, FCVT_L_D, FCVT_LU_D, 58 | FCVT_S_W, FCVT_S_WU, FCVT_S_L, FCVT_S_LU, 59 | FCVT_W_S, FCVT_WU_S, FCVT_L_S, FCVT_LU_S, 60 | FCVT_D_S, FCVT_S_D, 61 | }; 62 | 63 | typedef struct { 64 | char no; // 0~31 65 | } Reg; 66 | 67 | enum RoundMode { 68 | NOROUND = -1, 69 | RNE, // Round to Nearest, ties to Even 70 | RTZ, // Round towards Zero 71 | RDN, // Round Down (towards -Inf) 72 | RUP, // Round Up (towards +Inf) 73 | RMM, // Round to Nearest, ties to Max Magnitude 74 | }; 75 | 76 | enum OperandType { 77 | NOOPERAND, 78 | REG, // reg 79 | IMMEDIATE, // 1234 80 | DIRECT, // foobar + 345 81 | INDIRECT, // ofs(reg) 82 | FREG, // freg 83 | ROUNDMODE, // rm 84 | }; 85 | 86 | typedef struct Operand { 87 | enum OperandType type; 88 | union { 89 | Reg reg; 90 | int64_t immediate; 91 | struct { 92 | Expr *expr; 93 | } direct; 94 | struct { 95 | Expr *offset; 96 | Reg reg; 97 | } indirect; 98 | int freg; 99 | enum RoundMode roundmode; 100 | }; 101 | } Operand; 102 | 103 | typedef struct Inst { 104 | enum Opcode op; 105 | Operand opr[3]; 106 | } Inst; 107 | -------------------------------------------------------------------------------- /src/as/as_util.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "as_util.h" 3 | 4 | #ifndef ELF_NOT_SUPPORTED 5 | 6 | #include 7 | #include 8 | #include // realloc 9 | #include // memcpy 10 | 11 | #include "util.h" 12 | 13 | void strtab_init(Strtab *strtab) { 14 | table_init(&strtab->offsets); 15 | strtab->size = 0; 16 | } 17 | 18 | size_t strtab_add(Strtab *strtab, const Name *name) { 19 | void *result; 20 | if (!table_try_get(&strtab->offsets, name, &result)) { 21 | size_t offset = strtab->size; 22 | table_put(&strtab->offsets, name, (void*)offset); 23 | strtab->size += name->bytes + 1; 24 | return offset; 25 | } else { 26 | return (size_t)result; 27 | } 28 | } 29 | 30 | void *strtab_dump(Strtab *strtab) { 31 | void *buf = malloc_or_die(strtab->size); 32 | unsigned char *p = buf; 33 | const Name *name; 34 | void *value; 35 | for (int it = 0; (it = table_iterate(&strtab->offsets, it, &name, &value)) != -1; ) { 36 | uintptr_t offset = VOIDP2UINT(value); 37 | memcpy(p + offset, name->chars, name->bytes); 38 | p[offset + name->bytes] = '\0'; 39 | } 40 | return buf; 41 | } 42 | #endif // !ELF_NOT_SUPPORTED 43 | -------------------------------------------------------------------------------- /src/as/as_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | #include "table.h" 6 | 7 | // String table. 8 | typedef struct { 9 | Table offsets; 10 | size_t size; 11 | } Strtab; 12 | 13 | void strtab_init(Strtab *strtab); 14 | size_t strtab_add(Strtab *strtab, const Name *name); 15 | void *strtab_dump(Strtab *strtab); 16 | -------------------------------------------------------------------------------- /src/as/asm_code.h: -------------------------------------------------------------------------------- 1 | // Generate code for each architecture. 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | typedef struct Inst Inst; 8 | typedef struct ParseInfo ParseInfo; 9 | 10 | #define INST_LONG_OFFSET (1 << 0) // 32bit offset on jump, etc. 11 | 12 | typedef struct Code { 13 | Inst *inst; 14 | char flag; 15 | char len; 16 | #if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 17 | unsigned char buf[26]; 18 | #else 19 | unsigned char buf[14]; 20 | #endif 21 | } Code; 22 | 23 | void assemble_inst(Inst *inst, ParseInfo *info, Code *code); 24 | 25 | #ifndef MAKE_CODE 26 | #define MAKE_CODE(inst, code, ...) do { unsigned char buf[] = {__VA_ARGS__}; make_code(inst, code, buf, sizeof(buf)); } while (0) 27 | #endif 28 | 29 | #ifndef MAKE_CODE16 30 | #define MAKE_CODE16(inst, code, ...) do { unsigned short buf[] = {__VA_ARGS__}; make_code16(inst, code, buf, sizeof(buf)); } while (0) 31 | #endif 32 | 33 | #ifndef MAKE_CODE32 34 | #define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) 35 | #endif 36 | 37 | #define IM8(x) (x) 38 | #define IM16(x) (x), ((x) >> 8) 39 | #define IM32(x) (x), ((x) >> 8), ((x) >> 16), ((x) >> 24) 40 | #define IM64(x) (x), ((x) >> 8), ((x) >> 16), ((x) >> 24), ((x) >> 32), ((x) >> 40), ((x) >> 48), ((x) >> 56) 41 | 42 | void make_code(Inst *inst, Code *code, unsigned char *buf, int len); 43 | void make_code16(Inst *inst, Code *code, unsigned short *buf, int len); 44 | void make_code32(Inst *inst, Code *code, unsigned int *buf, int len); 45 | -------------------------------------------------------------------------------- /src/as/ir_asm.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "ir_asm.h" 3 | 4 | #include "util.h" 5 | 6 | IR *new_ir_label(const Name *label) { 7 | IR *ir = calloc_or_die(sizeof(*ir)); 8 | ir->kind = IR_LABEL; 9 | ir->label = label; 10 | return ir; 11 | } 12 | 13 | IR *new_ir_code(const Code *code) { 14 | IR *ir = calloc_or_die(sizeof(*ir)); 15 | ir->kind = IR_CODE; 16 | ir->code = *code; 17 | return ir; 18 | } 19 | 20 | IR *new_ir_data(const void *data, size_t size) { 21 | IR *ir = calloc_or_die(sizeof(*ir)); 22 | ir->kind = IR_DATA; 23 | ir->data.len = size; 24 | ir->data.buf = (unsigned char*)data; 25 | return ir; 26 | } 27 | 28 | IR *new_ir_bss(size_t size) { 29 | IR *ir = calloc_or_die(sizeof(*ir)); 30 | ir->kind = IR_BSS; 31 | ir->bss = size; 32 | return ir; 33 | } 34 | 35 | IR *new_ir_zero(size_t size) { 36 | IR *ir = calloc_or_die(sizeof(*ir)); 37 | ir->kind = IR_ZERO; 38 | ir->zero = size; 39 | return ir; 40 | } 41 | 42 | IR *new_ir_align(int align) { 43 | IR *ir = calloc_or_die(sizeof(*ir)); 44 | ir->kind = IR_ALIGN; 45 | ir->align = align; 46 | return ir; 47 | } 48 | 49 | IR *new_ir_expr(enum IrKind kind, const Expr *expr) { 50 | IR *ir = calloc_or_die(sizeof(*ir)); 51 | ir->kind = kind; 52 | ir->expr.expr = expr; 53 | ir->expr.addend = 0; 54 | return ir; 55 | } 56 | -------------------------------------------------------------------------------- /src/as/ir_asm.h: -------------------------------------------------------------------------------- 1 | // Intermediate Representation for assembly 2 | 3 | #pragma once 4 | 5 | #include // size_t 6 | #include // uint64_t 7 | 8 | #include "asm_code.h" // Code 9 | 10 | #define BYTE_SIZE (1) 11 | #define SHORT_SIZE (2) 12 | #define LONG_SIZE (4) 13 | #define QUAD_SIZE (8) 14 | 15 | typedef struct Expr Expr; 16 | typedef struct Name Name; 17 | typedef struct SectionInfo SectionInfo; 18 | typedef struct Table Table; 19 | typedef struct Vector Vector; 20 | 21 | enum UnresolvedKind { 22 | UNRES_EXTERN, 23 | UNRES_EXTERN_PC32, 24 | UNRES_ABS64, 25 | UNRES_CALL, 26 | UNRES_PCREL_HI, 27 | UNRES_PCREL_LO, 28 | UNRES_GOT_HI, 29 | UNRES_GOT_LO, 30 | 31 | UNRES_X64_GOT_LOAD, 32 | 33 | UNRES_RISCV_BRANCH, 34 | UNRES_RISCV_JAL, 35 | UNRES_RISCV_HI20, 36 | UNRES_RISCV_LO12_I, 37 | UNRES_RISCV_RVC_BRANCH, 38 | UNRES_RISCV_RVC_JUMP, 39 | UNRES_RISCV_RELAX, 40 | }; 41 | 42 | typedef struct { 43 | const Name *label; 44 | uintptr_t offset; 45 | SectionInfo *src_section; 46 | int add; 47 | enum UnresolvedKind kind; 48 | } UnresolvedInfo; 49 | 50 | typedef struct { 51 | size_t len; 52 | unsigned char *buf; 53 | } Data; 54 | 55 | enum IrKind { 56 | IR_LABEL, 57 | IR_CODE, 58 | IR_DATA, 59 | IR_BSS, 60 | IR_ZERO, 61 | IR_ALIGN, 62 | IR_EXPR_BYTE, 63 | IR_EXPR_SHORT, 64 | IR_EXPR_LONG, 65 | IR_EXPR_QUAD, 66 | }; 67 | 68 | typedef struct { 69 | enum IrKind kind; 70 | union { 71 | const Name *label; 72 | Code code; 73 | Data data; 74 | struct { 75 | const Expr *expr; 76 | int64_t addend; // Calculated in `resolve_relative_address` 77 | } expr; 78 | size_t bss; 79 | size_t zero; 80 | int align; 81 | int section; 82 | }; 83 | uint64_t address; 84 | } IR; 85 | 86 | IR *new_ir_label(const Name *label); 87 | IR *new_ir_code(const Code *code); 88 | IR *new_ir_data(const void *data, size_t size); 89 | IR *new_ir_bss(size_t size); 90 | IR *new_ir_zero(size_t size); 91 | IR *new_ir_align(int align); 92 | IR *new_ir_expr(enum IrKind kind, const Expr *expr); 93 | 94 | bool calc_label_address(uint64_t start_address, Vector *sections, Table *label_table); 95 | bool resolve_relative_address(Vector *sections, Table *label_table, Vector *unresolved); 96 | void emit_irs(Vector *sections); 97 | -------------------------------------------------------------------------------- /src/cc/arch/aarch64/arch_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Configuration for aarch64 4 | 5 | #define MAX_REG_ARGS (8) 6 | #define MAX_FREG_ARGS (8) 7 | 8 | #define PHYSICAL_REG_TEMPORARY (11) 9 | #define PHYSICAL_REG_MAX (PHYSICAL_REG_TEMPORARY + 17) 10 | #define PHYSICAL_FREG_TEMPORARY (8) 11 | #define PHYSICAL_FREG_MAX (PHYSICAL_FREG_TEMPORARY + 24) 12 | 13 | #define GET_FPREG_INDEX() 21 14 | -------------------------------------------------------------------------------- /src/cc/arch/riscv64/arch_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Configuration for riscv64 4 | 5 | #define MAX_REG_ARGS (8) 6 | #define MAX_FREG_ARGS (8) 7 | 8 | #define PHYSICAL_REG_TEMPORARY (8) 9 | #define PHYSICAL_REG_MAX (PHYSICAL_REG_TEMPORARY + 18) 10 | #define PHYSICAL_FREG_TEMPORARY (8) 11 | #define PHYSICAL_FREG_MAX (PHYSICAL_FREG_TEMPORARY + 24) 12 | 13 | #define GET_FPREG_INDEX() 18 14 | -------------------------------------------------------------------------------- /src/cc/arch/x64/arch_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Configuration for x64 4 | 5 | #define MAX_REG_ARGS (6) 6 | #define MAX_FREG_ARGS (8) 7 | 8 | #define PHYSICAL_REG_TEMPORARY (7) 9 | #define PHYSICAL_REG_MAX (PHYSICAL_REG_TEMPORARY + 8) 10 | #define PHYSICAL_FREG_TEMPORARY (8) 11 | #define PHYSICAL_FREG_MAX (PHYSICAL_FREG_TEMPORARY + 8) 12 | -------------------------------------------------------------------------------- /src/cc/backend/codegen.h: -------------------------------------------------------------------------------- 1 | // Code generation 2 | 3 | #pragma once 4 | 5 | #include 6 | #include // size_t 7 | 8 | #include "ir.h" // enum VRegSize 9 | 10 | typedef struct BB BB; 11 | typedef struct Expr Expr; 12 | typedef struct Function Function; 13 | typedef struct RegAlloc RegAlloc; 14 | typedef struct Stmt Stmt; 15 | typedef struct StructInfo StructInfo; 16 | typedef struct Type Type; 17 | typedef struct VReg VReg; 18 | typedef struct VarInfo VarInfo; 19 | typedef struct Vector Vector; 20 | 21 | // Public 22 | 23 | void gen(Vector *decls); 24 | 25 | // Private 26 | 27 | VReg *gen_expr(Expr *expr); 28 | 29 | void gen_cond_jmp(Expr *cond, BB *tbb, BB *fbb); 30 | 31 | void set_curbb(BB *bb); 32 | VReg *add_new_vreg(const Type *type); 33 | enum VRegSize to_vsize(const Type *type); 34 | int to_vflag(const Type *type); 35 | 36 | bool is_stack_param(const Type *type); 37 | 38 | void gen_stmt(struct Stmt *stmt); 39 | VReg *gen_stmts(Vector *stmts); 40 | VReg *gen_block(Stmt *stmt); 41 | 42 | typedef VReg *(*BuiltinFunctionProc)(Expr *expr); 43 | void add_builtin_function(const char *str, Type *type, BuiltinFunctionProc *proc, 44 | bool add_to_scope); 45 | 46 | void gen_clear_local_var(const VarInfo *varinfo); 47 | void gen_memcpy(const Type *type, VReg *dst, VReg *src); 48 | 49 | typedef struct { 50 | const Type *type; 51 | VReg *vreg; 52 | int index; 53 | } RegParamInfo; 54 | 55 | void enumerate_register_params( 56 | Function *func, RegParamInfo iargs[], int max_ireg, RegParamInfo fargs[], int max_freg, 57 | int *piarg_count, int *pfarg_count); 58 | 59 | bool gen_defun(Function *func); 60 | void prepare_register_allocation(Function *func); 61 | void map_virtual_to_physical_registers(RegAlloc *ra); 62 | void detect_living_registers(RegAlloc *ra, BBContainer *bbcon); 63 | void alloc_stack_variables_onto_stack_frame(Function *func); 64 | 65 | int calculate_func_param_bottom(Function *func); 66 | -------------------------------------------------------------------------------- /src/cc/backend/optimize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct Vector BBContainer; 4 | typedef struct RegAlloc RegAlloc; 5 | 6 | void optimize(RegAlloc *ra, BBContainer *bbcon); 7 | -------------------------------------------------------------------------------- /src/cc/backend/regalloc.h: -------------------------------------------------------------------------------- 1 | // Register allocation 2 | 3 | #pragma once 4 | 5 | #include 6 | #include // size_t 7 | 8 | #include "ir.h" // enum VRegSize 9 | 10 | typedef struct Vector BBContainer; 11 | typedef struct Function Function; 12 | typedef struct IR IR; 13 | typedef struct VReg VReg; 14 | typedef struct Vector Vector; 15 | 16 | enum LiveIntervalState { 17 | LI_NORMAL, 18 | LI_SPILL, 19 | }; 20 | 21 | typedef struct LiveInterval { 22 | unsigned long occupied_reg_bit; // Represent occupied registers in bit. 23 | enum LiveIntervalState state; 24 | int start; 25 | int end; 26 | int virt; // Virtual register no. 27 | int phys; // Mapped physical register no. 28 | } LiveInterval; 29 | 30 | typedef struct RegAllocSettings { 31 | unsigned long (*detect_extra_occupied)(RegAlloc *ra, IR *ir); 32 | const int *reg_param_mapping; 33 | int phys_max; // Max physical register count. 34 | int phys_temporary_count; // Temporary register count (= start index for saved registers) 35 | int fphys_max; // Floating-point register. 36 | int fphys_temporary_count; 37 | } RegAllocSettings; 38 | 39 | #define RAF_STACK_FRAME (1 << 0) // Require stack frame 40 | 41 | typedef struct RegAlloc { 42 | const RegAllocSettings *settings; 43 | Vector *vregs; // , non-const vregs 44 | Vector *consts; // , const vregs 45 | Vector **vreg_table; // [original_vreg_count] 46 | LiveInterval *intervals; // size=vregs->len 47 | LiveInterval **sorted_intervals; 48 | 49 | unsigned long used_reg_bits; 50 | unsigned long used_freg_bits; 51 | int flag; 52 | int original_vreg_count; 53 | } RegAlloc; 54 | 55 | RegAlloc *new_reg_alloc(const RegAllocSettings *settings); 56 | VReg *reg_alloc_spawn_raw(enum VRegSize vsize, int vflag); 57 | VReg *reg_alloc_spawn(RegAlloc *ra, enum VRegSize vsize, int vflag); 58 | VReg *reg_alloc_with_original(RegAlloc *ra, VReg *original); 59 | VReg *reg_alloc_spawn_const(RegAlloc *ra, int64_t value, enum VRegSize vsize); 60 | #ifndef __NO_FLONUM 61 | VReg *reg_alloc_spawn_fconst(RegAlloc *ra, double value, enum VRegSize vsize); 62 | #endif 63 | void alloc_physical_registers(RegAlloc *ra, BBContainer *bbcon); 64 | -------------------------------------------------------------------------------- /src/cc/backend/ssa.h: -------------------------------------------------------------------------------- 1 | // Static Single Assignment 2 | 3 | #pragma once 4 | 5 | typedef struct Vector BBContainer; 6 | typedef struct RegAlloc RegAlloc; 7 | 8 | void make_ssa(RegAlloc *ra, BBContainer *bbcon); 9 | void resolve_phis(RegAlloc *ra, BBContainer *bbcon); 10 | -------------------------------------------------------------------------------- /src/cc/frontend/cc_misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // size_t 5 | #include 6 | 7 | typedef struct Expr Expr; 8 | typedef struct Initializer Initializer; 9 | typedef struct Type Type; 10 | typedef struct VarInfo VarInfo; 11 | 12 | bool is_function_omitted(const VarInfo *funcvi); 13 | 14 | typedef struct { 15 | void (*emit_align)(void *ud, int align); 16 | void (*emit_number)(void *ud, const Type *type, Expr *var, int64_t offset); // Flonum is passed as a hexvalue. 17 | void (*emit_string)(void *ud, Expr *str, size_t size); 18 | } ConstructInitialValueVTable; 19 | void construct_initial_value(const Type *type, const Initializer *init, 20 | const ConstructInitialValueVTable *vtable, void *ud); 21 | -------------------------------------------------------------------------------- /src/cc/frontend/initializer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct Expr Expr; 4 | typedef struct Initializer Initializer; 5 | typedef struct Scope Scope; 6 | typedef struct Token Token; 7 | typedef struct Type Type; 8 | typedef struct Vector Vector; 9 | 10 | Type *fix_array_size(Type *type, Initializer *init, const Token *token); 11 | Expr *str_to_char_array_var(Scope *scope, Expr *str); 12 | void construct_initializing_stmts(Vector *decls); 13 | Vector *assign_initial_value(Expr *expr, Initializer *init, Vector *inits); 14 | Initializer *flatten_initializer(Type *type, Initializer *init); 15 | Initializer *check_vardecl(Type **ptype, const Token *ident, int storage, Initializer *init); 16 | -------------------------------------------------------------------------------- /src/cc/frontend/lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // FILE 5 | 6 | #include "ast.h" // Token, TokenKind 7 | 8 | #define MAX_LEX_LOOKAHEAD (3) 9 | 10 | typedef struct Line Line; 11 | typedef struct Name Name; 12 | 13 | typedef struct { 14 | FILE *fp; 15 | const char *filename; 16 | Line *line; 17 | const char *p; 18 | Token *fetched[MAX_LEX_LOOKAHEAD]; 19 | int idx; 20 | int lineno; 21 | } Lexer; 22 | 23 | void init_lexer(void); 24 | void init_lexer_for_preprocessor(void); 25 | void set_source_file(FILE *fp, const char *filename); 26 | void set_source_string(const char *line, const char *filename, int lineno); 27 | Token *fetch_token(void); 28 | Token *match(enum TokenKind kind); 29 | void unget_token(Token *token); 30 | const char *read_ident(const char *p); 31 | Token *alloc_dummy_ident(void); 32 | const char *get_lex_p(void); 33 | _Noreturn void lex_error(const char *p, const char *fmt, ...); 34 | 35 | typedef bool (*LexEofCallback)(void); 36 | LexEofCallback set_lex_eof_callback(LexEofCallback callback); 37 | bool lex_eof_continue(void); 38 | -------------------------------------------------------------------------------- /src/cc/frontend/parser.h: -------------------------------------------------------------------------------- 1 | // Parser 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | #include "ast.h" // TokenKind 8 | 9 | typedef struct Expr Expr; 10 | typedef struct Initializer Initializer; 11 | typedef struct Stmt Stmt; 12 | typedef struct Token Token; 13 | typedef struct Type Type; 14 | typedef struct Vector Vector; 15 | 16 | void parse(Vector *decls); // 17 | 18 | // 19 | 20 | typedef Expr *(*BuiltinExprProc)(const Token*); 21 | void add_builtin_expr_ident(const char *str, BuiltinExprProc *proc); 22 | 23 | Type *parse_raw_type(int *pstorage); 24 | Type *parse_type_suffix(Type *type); 25 | Type *parse_declarator(Type *rawtype, Token **pident); 26 | Type *parse_direct_declarator(Type *type, Token **pident); 27 | Vector *parse_args(Token **ptoken); 28 | Vector *parse_funparams(bool *pvaargs); // Vector, NULL=>old style. 29 | Type *parse_var_def(Type **prawType, int *pstorage, Token **pident); 30 | Expr *parse_const_fixnum(void); 31 | Expr *parse_assign(void); 32 | Expr *parse_expr(void); 33 | Stmt *parse_block(const Token *tok, Scope *scope); 34 | Initializer *parse_initializer(void); 35 | 36 | Token *consume(enum TokenKind kind, const char *error); 37 | -------------------------------------------------------------------------------- /src/cpp/cpp.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "preprocessor.h" 7 | #include "util.h" 8 | 9 | static void usage(FILE *fp) { 10 | fprintf( 11 | fp, 12 | "Usage: cpp [options] file...\n" 13 | "Options:\n" 14 | " -D Define label\n" 15 | " -I Add include path\n" 16 | " -isystem Add system include path\n" 17 | " -idirafter Add include path (lower priority)\n" 18 | " -C Preserve comments\n" 19 | ); 20 | } 21 | 22 | int main(int argc, char *argv[]) { 23 | FILE *ofp = stdout; 24 | init_preprocessor(ofp); 25 | 26 | enum { 27 | OPT_HELP = 128, 28 | OPT_VERSION, 29 | OPT_ISYSTEM, 30 | OPT_IDIRAFTER, 31 | }; 32 | 33 | static const struct option options[] = { 34 | {"I", required_argument}, // Add include path 35 | {"isystem", required_argument, OPT_ISYSTEM}, // Add system include path 36 | {"idirafter", required_argument, OPT_IDIRAFTER}, // Add include path (after) 37 | {"D", required_argument}, // Define macro 38 | {"U", required_argument}, // Undefine macro 39 | {"C", no_argument}, // Do not discard comments 40 | {"-help", no_argument, OPT_HELP}, 41 | {"v", no_argument, OPT_VERSION}, 42 | {"-version", no_argument, OPT_VERSION}, 43 | {0}, 44 | }; 45 | int opt; 46 | while ((opt = optparse(argc, argv, options)) != -1) { 47 | switch (opt) { 48 | default: assert(false); break; 49 | case OPT_HELP: 50 | usage(stdout); 51 | return 0; 52 | case OPT_VERSION: 53 | show_version("cpp", -1); 54 | return 0; 55 | case 'I': 56 | add_inc_path(INC_NORMAL, optarg); 57 | break; 58 | case OPT_ISYSTEM: 59 | add_inc_path(INC_SYSTEM, optarg); 60 | break; 61 | case OPT_IDIRAFTER: 62 | add_inc_path(INC_AFTER, optarg); 63 | break; 64 | case 'D': 65 | define_macro(optarg); 66 | break; 67 | case 'U': 68 | undef_macro(optarg, NULL); 69 | break; 70 | case 'C': 71 | set_preserve_comment(true); 72 | break; 73 | case '?': 74 | fprintf(stderr, "Warning: unknown option: %s\n", argv[optind - 1]); 75 | break; 76 | } 77 | } 78 | 79 | int iarg = optind; 80 | if (iarg < argc) { 81 | for (int i = iarg; i < argc; ++i) { 82 | const char *filename = argv[i]; 83 | FILE *fp; 84 | if (!is_file(filename) || (fp = fopen(filename, "r")) == NULL) 85 | error("Cannot open file: %s\n", filename); 86 | preprocess(fp, filename); 87 | fclose(fp); 88 | } 89 | } else { 90 | preprocess(stdin, "*stdin*"); 91 | } 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /src/cpp/macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct Name Name; 4 | typedef struct Table Table; 5 | typedef struct Vector Vector; 6 | 7 | typedef struct Macro { 8 | Table *param_table; // key=variable name, value=parameter index 9 | int params_len; // -1 => no param macro 10 | const Name *vaargs_ident; 11 | Vector *body; // 12 | } Macro; 13 | 14 | Macro *new_macro(Vector *params, const Name *vaargs_ident, Vector *body); 15 | 16 | // 17 | 18 | void macro_init(void); 19 | void macro_add(const Name *name, Macro *macro); 20 | Macro *macro_get(const Name *name); 21 | void macro_delete(const Name *name); 22 | void macro_expand(Vector *tokens); 23 | -------------------------------------------------------------------------------- /src/cpp/pp_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // int64_t 4 | #include // FILE 5 | 6 | #include "lexer.h" // TokenKind, Token 7 | 8 | typedef struct Macro Macro; 9 | typedef struct Vector Vector; 10 | 11 | typedef int64_t PpResult; 12 | 13 | typedef struct { 14 | const char *filename; 15 | FILE *fp; 16 | int lineno; 17 | } Stream; 18 | 19 | Stream *set_pp_stream(Stream *stream); 20 | PpResult pp_expr(void); 21 | Vector *pp_funargs(Vector *tokens, int *pindex, int vaarg); // > 22 | 23 | Token *pp_match(enum TokenKind kind); 24 | Token *pp_consume(enum TokenKind kind, const char *error); 25 | 26 | _Noreturn void pp_parse_error(const Token *token, const char *fmt, ...); 27 | 28 | Macro *can_expand_ident(const Name *ident); 29 | void push_lex(const Name *ident, void (*callback)(void)); 30 | -------------------------------------------------------------------------------- /src/cpp/preprocessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // FILE* 5 | 6 | enum IncludeOrder { 7 | INC_NORMAL, 8 | INC_SYSTEM, 9 | INC_AFTER, 10 | }; 11 | 12 | void init_preprocessor(FILE *ofp); 13 | void set_preserve_comment(bool enable); 14 | void preprocess(FILE *fp, const char *filename); 15 | 16 | void define_macro(const char *arg); // "FOO" or "BAR=QUX" 17 | void undef_macro(const char *begin, const char *end); 18 | void add_inc_path(enum IncludeOrder order, const char *path); 19 | 20 | // Handle preprocessor directives and 21 | // returns non-directive next line. 22 | // NULL: EOF 23 | const char *get_processed_next_line(void); 24 | -------------------------------------------------------------------------------- /src/ld/elfobj.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined(__linux__) 8 | #include 9 | #else 10 | #include "../../include/elf.h" 11 | #endif 12 | 13 | typedef struct Name Name; 14 | typedef struct Table Table; 15 | typedef struct Vector Vector; 16 | 17 | typedef struct ElfSectionInfo { 18 | struct ElfObj *elfobj; 19 | Elf64_Shdr *shdr; 20 | union { 21 | struct { 22 | uintptr_t address; 23 | unsigned char *content; 24 | } progbits; 25 | struct { 26 | const char *buf; 27 | } strtab; 28 | struct { 29 | Elf64_Sym *syms; 30 | struct ElfSectionInfo *strtab; 31 | size_t count; 32 | } symtab; 33 | }; 34 | } ElfSectionInfo; 35 | 36 | typedef struct ElfObj { 37 | FILE *fp; 38 | size_t start_offset; 39 | Elf64_Ehdr ehdr; 40 | Elf64_Shdr *shdrs; 41 | Table *symbol_table; // , global only 42 | 43 | Vector *prog_sections; // , PROGBITS, NOBITS, INIT_ARRAY, FINI_ARRAY, PREINIT_ARRAY 44 | ElfSectionInfo *section_infos; 45 | ElfSectionInfo *symtab_section; 46 | int nobit_shndx; 47 | } ElfObj; 48 | 49 | ElfObj *read_elf(FILE *fp, const char *fn); 50 | void close_elf(ElfObj *elfobj); 51 | Elf64_Sym *elfobj_find_symbol(ElfObj *elfobj, const Name *name); 52 | -------------------------------------------------------------------------------- /src/util/archive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "table.h" 7 | 8 | typedef struct Vector Vector; 9 | 10 | typedef struct { 11 | void *obj; 12 | size_t size; 13 | uint32_t file_offset; 14 | char name[16]; 15 | } ArContent; 16 | 17 | typedef struct { 18 | ArContent *content; 19 | } ArSymbol; 20 | 21 | typedef struct { 22 | FILE *fp; 23 | uint32_t symbol_count; 24 | ArSymbol *symbols; 25 | Table symbol_table; 26 | Vector *contents; // 27 | } Archive; 28 | 29 | Archive *load_archive(const char *filename); 30 | void *load_archive_content(Archive *ar, ArSymbol *symbol, 31 | void *(*load)(FILE*, const char*, size_t)); 32 | 33 | #define FOREACH_FILE_ARCONTENT(ar, content, body) \ 34 | {Vector *contents = (ar)->contents; \ 35 | for (int _ic = 0; _ic < contents->len; _ic += 1) { \ 36 | ArContent *content = contents->data[_ic]; \ 37 | body \ 38 | }} 39 | -------------------------------------------------------------------------------- /src/util/elfutil.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "elfutil.h" 3 | 4 | #ifndef ELF_NOT_SUPPORTED 5 | void out_elf_header(FILE *fp, uintptr_t entry, int phnum, int shnum, int flags, uintptr_t shoff) { 6 | Elf64_Ehdr ehdr = { 7 | .e_ident = { ELFMAG0, ELFMAG1, ELFMAG2 ,ELFMAG3, 8 | ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV }, 9 | .e_type = phnum > 0 ? ET_EXEC : ET_REL, 10 | .e_machine = MACHINE_TYPE, 11 | .e_version = EV_CURRENT, 12 | .e_entry = entry, 13 | .e_phoff = phnum > 0 ? sizeof(Elf64_Ehdr) : 0, 14 | .e_shoff = shoff, 15 | .e_flags = flags, 16 | .e_ehsize = sizeof(Elf64_Ehdr), 17 | .e_phentsize = phnum > 0 ? sizeof(Elf64_Phdr) : 0, 18 | .e_phnum = phnum, 19 | .e_shentsize = shnum > 0 ? sizeof(Elf64_Shdr) : 0, 20 | .e_shnum = shnum, 21 | .e_shstrndx = shnum > 0 ? shnum - 1 : SHN_UNDEF, // Assumes shstrndx is at last. 22 | }; 23 | 24 | fwrite(&ehdr, sizeof(Elf64_Ehdr), 1, fp); 25 | } 26 | 27 | void out_program_header(FILE *fp, int sec, uintptr_t offset, uintptr_t vaddr, size_t filesz, 28 | size_t memsz) { 29 | static const int kFlags[] = { 30 | PF_R | PF_X, // code 31 | PF_R | PF_W, // rwdata 32 | }; 33 | 34 | Elf64_Phdr phdr = { 35 | .p_type = PT_LOAD, 36 | .p_offset = offset, 37 | .p_vaddr = vaddr, 38 | .p_paddr = vaddr, // dummy 39 | .p_filesz = filesz, 40 | .p_memsz = memsz, 41 | .p_flags = kFlags[sec], 42 | .p_align = 0x1000, 43 | }; 44 | 45 | fwrite(&phdr, sizeof(Elf64_Phdr), 1, fp); 46 | } 47 | #endif // !ELF_NOT_SUPPORTED 48 | -------------------------------------------------------------------------------- /src/util/elfutil.h: -------------------------------------------------------------------------------- 1 | // ELF format utility 2 | 3 | #pragma once 4 | 5 | #include // FILE 6 | 7 | #ifdef __APPLE__ 8 | #include "../../include/elf.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | void out_elf_header(FILE *fp, uintptr_t entry, int phnum, int shnum, int flags, uintptr_t shoff); 14 | void out_program_header(FILE *fp, int sec, uintptr_t offset, uintptr_t vaddr, size_t filesz, 15 | size_t memsz); 16 | -------------------------------------------------------------------------------- /src/util/table.h: -------------------------------------------------------------------------------- 1 | // Hash Table 2 | 3 | #pragma once 4 | 5 | #include 6 | #include // uint32_t 7 | 8 | // Name 9 | 10 | typedef struct Name { 11 | const char *chars; 12 | int bytes; 13 | uint32_t hash; 14 | } Name; 15 | 16 | const Name *alloc_name(const char *begin, const char *end, bool make_copy); 17 | bool equal_name(const Name *name1, const Name *name2); 18 | 19 | // For printf, usage: printf("%.*s\n", NAMES(name)) 20 | #define NAMES(name) ((name)->bytes), ((name)->chars) 21 | 22 | // Hash Table 23 | 24 | typedef struct TableEntry { 25 | const Name *key; 26 | void *value; 27 | } TableEntry; 28 | 29 | typedef struct Table { 30 | TableEntry *entries; 31 | int capacity; 32 | int count; 33 | int used; // Include tombstone count. 34 | } Table; 35 | 36 | Table *alloc_table(void); 37 | void table_init(Table *table); 38 | void *table_get(Table *table, const Name *key); 39 | bool table_try_get(Table *table, const Name *key, void **output); 40 | bool table_put(Table *table, const Name *key, void *value); 41 | bool table_delete(Table *table, const Name *key); 42 | int table_iterate(Table *table, int iterator, const Name **name, void **value); // -1 => end 43 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define VERSION "0.1.1" 4 | -------------------------------------------------------------------------------- /src/wcc/wasm_linker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "table.h" 8 | 9 | typedef struct File File; 10 | typedef struct Vector Vector; 11 | 12 | #define WASI_MODULE_NAME "wasi_snapshot_preview1" 13 | 14 | typedef struct { 15 | Vector *files; // 16 | Table defined, unresolved; // 17 | Vector *indirect_functions; // public/static indirect functions, 18 | uint32_t unresolved_func_count; 19 | uint32_t address_bottom; 20 | 21 | const Name *sp_name; 22 | const Name *curbrk_name; 23 | 24 | FILE *ofp; 25 | } WasmLinker; 26 | 27 | void linker_init(WasmLinker *linker); 28 | bool read_wasm_obj(WasmLinker *linker, const char *filename); 29 | bool link_wasm_objs(WasmLinker *linker, Vector *exports, uint32_t stack_size); 30 | bool linker_emit_wasm(WasmLinker *linker, const char *ofn, Vector *exports); 31 | -------------------------------------------------------------------------------- /src/wcc/www/@types/c.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.c' 2 | -------------------------------------------------------------------------------- /src/wcc/www/@types/patch.d.ts: -------------------------------------------------------------------------------- 1 | // Patches for type declarations. 2 | 3 | interface Window { 4 | initialData: any 5 | showOpenFilePicker(option?: any): Promise<[FileSystemFileHandle]> 6 | showSaveFilePicker(option?: any): Promise 7 | 8 | MonacoEnvironment: any 9 | require: any 10 | Alpine: any 11 | } 12 | 13 | interface FileSystemHandle { 14 | readonly kind: 'file' | 'directory' 15 | readonly name: string 16 | } 17 | 18 | interface FileSystemFileHandle extends FileSystemHandle { 19 | getFile(): Promise 20 | createWritable(): Promise 21 | } 22 | 23 | interface WritableStream { 24 | close(): any 25 | } 26 | 27 | interface FileSystemWritableFileStream extends WritableStream { 28 | write(content: any): Promise 29 | } 30 | 31 | declare let monaco: any 32 | -------------------------------------------------------------------------------- /src/wcc/www/examples/hello.c: -------------------------------------------------------------------------------- 1 | // Hello, world! 2 | 3 | #include 4 | 5 | int main(void) { 6 | printf("Hello, world!\n"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/wcc/www/examples/qsort.c: -------------------------------------------------------------------------------- 1 | // Function pointer example 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void dump(const char *title, int *array, int n) { 9 | printf("%s", title); 10 | for (int i = 0; i < n; ++i) 11 | printf("%d ", array[i]); 12 | printf("\n"); 13 | } 14 | 15 | int compare(const void *va, const void *vb) { 16 | const int *pa = va; 17 | const int *pb = vb; 18 | return *pa - *pb; 19 | } 20 | 21 | int main(int argc, char *argv[]) { 22 | int N = 10; 23 | if (argc > 1) 24 | N = atoi(argv[1]); 25 | 26 | srand(time(NULL)); 27 | 28 | int *array = alloca(sizeof(*array) * N); 29 | for (int i = 0; i < N; ++i) { 30 | array[i] = rand() % N; 31 | } 32 | 33 | dump("Before:", array, N); 34 | qsort(array, N, sizeof(*array), compare); 35 | dump("After :", array, N); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/wcc/www/examples/sieve.c: -------------------------------------------------------------------------------- 1 | // Malloc and pointer example 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void sieve(int n) { 9 | uint8_t *notprime = calloc(sizeof(*notprime), n); 10 | if (notprime == NULL) { 11 | exit(1); 12 | } 13 | 14 | for (int i = 2; i < n; ++i) { 15 | if (notprime[i]) 16 | continue; 17 | printf("%d\n", i); 18 | for (int j = i * i; j < n; j += i) 19 | notprime[j] = true; 20 | } 21 | free(notprime); 22 | } 23 | 24 | int main(int argc, char *argv[]) { 25 | int n = 100; 26 | if (argc > 1) { 27 | n = atoi(argv[1]); 28 | if (n < 2) { 29 | return 1; 30 | } 31 | } 32 | sieve(n); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/wcc/www/lib_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "usr": { 3 | "bin": { 4 | "cc": "./cc.wasm" 5 | }, 6 | "include": { 7 | "sys": { 8 | "random.h": "./include/sys/random.h", 9 | "stat.h": "./include/sys/stat.h", 10 | "types.h": "./include/sys/types.h" 11 | }, 12 | "alloca.h": "./include/alloca.h", 13 | "ar.h": "./include/ar.h", 14 | "assert.h": "./include/assert.h", 15 | "ctype.h": "./include/ctype.h", 16 | "errno.h": "./include/errno.h", 17 | "fcntl.h": "./include/fcntl.h", 18 | "float.h": "./include/float.h", 19 | "inttypes.h": "./include/inttypes.h", 20 | "libgen.h": "./include/libgen.h", 21 | "limits.h": "./include/limits.h", 22 | "math.h": "./include/math.h", 23 | "setjmp.h": "./include/setjmp.h", 24 | "stdarg.h": "./include/stdarg.h", 25 | "stdbool.h": "./include/stdbool.h", 26 | "stddef.h": "./include/stddef.h", 27 | "stdint.h": "./include/stdint.h", 28 | "stdio.h": "./include/stdio.h", 29 | "stdlib.h": "./include/stdlib.h", 30 | "stdnoreturn.h": "./include/stdnoreturn.h", 31 | "string.h": "./include/string.h", 32 | "strings.h": "./include/strings.h", 33 | "time.h": "./include/time.h", 34 | "unistd.h": "./include/unistd.h", 35 | "wasi.h": "./libsrc/_wasm/wasi.h", 36 | "wchar.h": "./include/wchar.h" 37 | }, 38 | "lib": { 39 | "wcrt0.a": "./lib/wcrt0.a", 40 | "wlibc.a": "./lib/wlibc.a" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/wcc/www/wa_proc.ts: -------------------------------------------------------------------------------- 1 | import {WASI} from '@wasmer/wasi' 2 | import {WasmFs} from '@wasmer/wasmfs' 3 | import path from 'path-browserify' 4 | 5 | export class WaProc { 6 | private memory: WebAssembly.Memory 7 | private cwd = '/' 8 | private imports: any 9 | private wasi: WASI 10 | 11 | constructor(private wasmFs: WasmFs, args: string[], curDir?: string) { 12 | if (curDir == null) 13 | curDir = '/' 14 | 15 | this.wasi = new WASI({ 16 | args, 17 | bindings: { 18 | ...WASI.defaultBindings, 19 | fs: this.wasmFs.fs, 20 | path, 21 | }, 22 | preopens: { 23 | '/': '/', 24 | '.': curDir, 25 | }, 26 | }) 27 | 28 | this.imports = { 29 | wasi_snapshot_preview1: this.wasi.wasiImport, 30 | } 31 | 32 | this.chdir(curDir) 33 | } 34 | 35 | public async runWasiEntry(wasmPath: string): Promise { 36 | const instance = await this.loadWasm(wasmPath) 37 | this.wasi.start(instance!) 38 | } 39 | 40 | private async loadWasm(wasmPath: string): Promise { 41 | let obj: WebAssembly.WebAssemblyInstantiatedSource 42 | if (typeof wasmPath === 'string') { 43 | const bin = this.wasmFs.fs.readFileSync(this.getAbsPath(wasmPath)) as Uint8Array 44 | 45 | if (bin == null) { 46 | throw 'File not found' 47 | } 48 | obj = await WebAssembly.instantiate(bin, this.imports) 49 | } else { 50 | console.error(`Path or buffer required: ${wasmPath}`) 51 | return null 52 | } 53 | const instance = obj.instance 54 | 55 | if (instance.exports.memory) { 56 | this.memory = instance.exports.memory as WebAssembly.Memory 57 | this.wasi.setMemory(this.memory) 58 | } 59 | return instance 60 | } 61 | 62 | private chdir(absPath: string): boolean { 63 | const st = this.wasmFs.fs.statSync(absPath) 64 | if (!st?.isDirectory()) 65 | return false 66 | this.cwd = absPath 67 | return true 68 | } 69 | 70 | private getAbsPath(fileName: string): string { 71 | if (fileName.length > 0 && fileName[0] === '/') 72 | return fileName 73 | // TODO: Handle ., .. 74 | //return `${this.cwd}/${fileName}` 75 | return `${this.cwd}${this.cwd === '/' ? '' : '/'}${fileName}` 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/example_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o pipefail 4 | 5 | source ./test_sub.sh 6 | 7 | function no_flonum() { 8 | echo -e "#include \nint main(){\n#ifdef __NO_FLONUM\nputs(\"true\");\n#endif\nreturn 0;}" | \ 9 | $XCC -xc - && ${RUN_EXE} ./a.out || exit 1 10 | } 11 | 12 | function test_all() { 13 | begin_test_suite "All" 14 | 15 | try_file 'hello' 'Hello, world!' ../examples/hello.c 16 | try_file 'fib' 832040 ../examples/fib.c 17 | try_file 'echo' 'foo bar baz' ../examples/echo.c foo bar baz 18 | 19 | if [ "$(no_flonum)" != "true" ]; then 20 | try_cmp 'mandelbrot' 'mandel256.ppm' 'mandelbrot.ppm' ../examples/mandelbrot.c 100 256 256 21 | fi 22 | 23 | end_test_suite 24 | } 25 | 26 | test_all 27 | 28 | if [[ $FAILED_SUITE_COUNT -ne 0 ]]; then 29 | exit "$FAILED_SUITE_COUNT" 30 | fi 31 | -------------------------------------------------------------------------------- /tests/fvaltest.c: -------------------------------------------------------------------------------- 1 | #ifdef __NO_FLONUM 2 | #include 3 | int main() { 4 | printf(" skipped\n"); 5 | return 0; 6 | } 7 | #else 8 | 9 | #ifdef USE_SINGLE 10 | typedef float Number; 11 | #define NUMBER_TYPE_SIZE (4) 12 | #else 13 | typedef double Number; 14 | #define NUMBER_TYPE_SIZE (8) 15 | 16 | double mix_params(int i0, double d0, int i1, float f1, int i2, double d2, int i3, float f3) { 17 | return (i0 * i1 * i2 * i3) / (d0 * f1 * d2 * f3); 18 | } 19 | 20 | double mix_many_params(int n, int i1, double d1, int i2, double d2, int i3, double d3, int i4, 21 | double d4, int i5, double d5, int i6, double d6) { 22 | (void)n; 23 | return i1 * d1 + i2 * d2 + i3 * d3 + i4 * d4 + i5 * d5 + i6 * d6; 24 | } 25 | #endif 26 | 27 | #include "flotest.inc" 28 | 29 | TEST(mix) { 30 | #ifndef USE_SINGLE 31 | EXPECT_NEAR(0.2734375, mix_params(1, 2, 3, 4, 5, 6, 7, 8)); 32 | EXPECT_NEAR(322.0, mix_many_params(20, 1, 2.0, 3, 4.0f, 5, 6.0, 7, 8.0f, 9, 10.0, 11, 12.0f)); 33 | 34 | { 35 | float a = 12.34f; 36 | a += 56.78; 37 | EXPECT_NEAR(69.12f, a); 38 | } 39 | 40 | { 41 | double d = 0xf123456789012345LLU; 42 | uint64_t x = d; 43 | char buf[32]; 44 | snprintf(buf, sizeof(buf), "%" PRIx64, x); 45 | EXPECT_STREQ("ulltof", "f123456789012000", buf); 46 | } 47 | #endif 48 | } 49 | 50 | XTEST_MAIN(); 51 | #endif 52 | -------------------------------------------------------------------------------- /tests/link_main.c: -------------------------------------------------------------------------------- 1 | // Compiled on XCC 2 | 3 | #include "stdio.h" 4 | #include "stdlib.h" // exit 5 | 6 | #define XTEST_NO_EXPECT_NEAR 7 | #include "./xtest.h" 8 | 9 | extern int array[]; 10 | extern int *ptr; 11 | extern int sq(int x); 12 | extern int ref_export(void); 13 | extern void store_common(int x); 14 | #ifndef __NO_FLONUM 15 | extern double many_fargs(double a, double b, double c, double d, double e, double f, double g, 16 | double h, double i); 17 | #endif 18 | 19 | int export_var = 9876; 20 | int common_var; 21 | 22 | TEST(all) { 23 | expecti64("external array", 222, array[2]); 24 | expecti64("external ptr", 333, ptr[3]); 25 | expecti64("funcall", 1234321, sq(1111)); 26 | expecti64("export_var", 9876, ref_export()); 27 | expecti64("common_var", 4567, (store_common(4567), common_var)); 28 | #ifndef __NO_FLONUM 29 | expectf64("many_dargs", 17.0, many_fargs(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)); 30 | #endif 31 | } 32 | 33 | XTEST_MAIN(); 34 | -------------------------------------------------------------------------------- /tests/link_sub.c: -------------------------------------------------------------------------------- 1 | // Compiled on gcc 2 | 3 | int array[] = {0, 111, 222, 333, 444, 555, 666, 777}; 4 | int *ptr = array; 5 | 6 | extern int export_var; 7 | int common_var; 8 | 9 | int sq(int x) { 10 | return x * x; 11 | } 12 | 13 | int ref_export(void) { 14 | return export_var; 15 | } 16 | 17 | void store_common(int x) { 18 | common_var = x; 19 | } 20 | 21 | #ifndef __NO_FLONUM 22 | double many_fargs(double a, double b, double c, double d, double e, double f, double g, double h, 23 | double i) { 24 | return h + i; 25 | } 26 | #endif 27 | -------------------------------------------------------------------------------- /tests/mandel256.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tyfkda/xcc/8c478ea28aaffb8b4bbf1d1320acaa6ebbe41662/tests/mandel256.ppm -------------------------------------------------------------------------------- /tests/table_test.c: -------------------------------------------------------------------------------- 1 | #include "table.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "./xtest.h" 9 | 10 | TEST(table) { 11 | const Name *key = alloc_name("1", NULL, false); 12 | 13 | Table table; 14 | table_init(&table); 15 | EXPECT_NULL(table_get(&table, key)); 16 | EXPECT_FALSE(table_delete(&table, key)); 17 | 18 | void *data = &table; 19 | table_put(&table, key, data); 20 | EXPECT_PTREQ(data, table_get(&table, key)); 21 | EXPECT_TRUE(table_try_get(&table, key, NULL)); 22 | EXPECT_EQ(1, table.count); 23 | 24 | const Name *key_dup = alloc_name("1", NULL, false); 25 | table_put(&table, key_dup, data); 26 | EXPECT_EQ(1, table.count); 27 | 28 | EXPECT_TRUE(table_delete(&table, key)); 29 | EXPECT_NULL(table_get(&table, key)); 30 | EXPECT_TRUE(!table_try_get(&table, key, NULL)); 31 | EXPECT_EQ(0, table.count); 32 | EXPECT_EQ(1, table.used); 33 | } 34 | 35 | XTEST_MAIN(); 36 | -------------------------------------------------------------------------------- /tests/thirdparty/cpython.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/python/cpython.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard c75330605d4795850ec74fdc4d69aa5d92f76c00 7 | 8 | # Python's './configure' command misidentifies chibicc as icc 9 | # (Intel C Compiler) because icc is a substring of chibicc. 10 | # Modify the configure file as a workaround. 11 | #sed -i -e 1996,2011d configure.ac 12 | autoreconf 13 | 14 | CC=$xcc ./configure 15 | $make clean 16 | $make 17 | $make test 18 | -------------------------------------------------------------------------------- /tests/thirdparty/git.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/git/git.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard 564d0252ca632e0264ed670534a51d18a689ef5d # 2023/11/20 v2.43.0 7 | 8 | $make clean 9 | $make V=1 CC="$xcc" 10 | $make V=1 CC="$xcc" test 11 | -------------------------------------------------------------------------------- /tests/thirdparty/libpng.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/rui314/libpng.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard dbe3e0c43e549a1602286144d94b0666549b18e6 7 | 8 | CC="$xcc" ./configure 9 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 10 | $make clean 11 | $make 12 | $make test 13 | -------------------------------------------------------------------------------- /tests/thirdparty/lua.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/lua/lua.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard 6443185167c77adcc8552a3fee7edab7895db1a9 # v5.4.6 7 | 8 | $make clean 9 | $make -j1 CC="$xcc" 10 | 11 | sed -i 's/ and when == "absent"//' testes/attrib.lua 12 | cd testes && ../lua all.lua 13 | -------------------------------------------------------------------------------- /tests/thirdparty/sqlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/sqlite/sqlite.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard 86f477edaa17767b39c7bae5b67cac8580f7a8c1 7 | 8 | CC="$xcc" ./configure --enable-shared=no 9 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 10 | $make clean 11 | $make 12 | $make test 13 | -------------------------------------------------------------------------------- /tests/thirdparty/thirdpartycommon: -------------------------------------------------------------------------------- 1 | make="make -j$(nproc)" 2 | xcc=$(cd "$(dirname "$0")/../../tool";pwd)/xccsh 3 | 4 | dir=$(basename -s .git "$repo") 5 | 6 | set -e -x 7 | 8 | REPOROOT=$(cd "$(dirname "$0")";pwd)/.external 9 | mkdir -p "$REPOROOT" 10 | cd "$REPOROOT" 11 | [ -d "$dir" ] || git clone "$repo" 12 | cd "$dir" 13 | -------------------------------------------------------------------------------- /tests/thirdparty/tinycc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | repo='https://github.com/TinyCC/tinycc.git' 5 | . tests/thirdparty/thirdpartycommon 6 | git reset --hard df67d8617b7d1d03a480a28f9f901848ffbfb7ec 7 | 8 | ./configure --cc=$xcc 9 | $make clean 10 | $make 11 | $make CC=cc test 12 | -------------------------------------------------------------------------------- /tool/diswasm.ts: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ts-node 2 | 3 | 'use strict' 4 | 5 | import fsPromise from 'node:fs/promises' 6 | import {DisWasm} from '../src/wcc/www/diswasm' 7 | 8 | async function main(argv: string[]) { 9 | const {program} = require('commander') 10 | program 11 | .option('--dump-addr', 'Dump address') 12 | .allowExcessArguments() 13 | .parse(argv) 14 | const opts = program.opts() 15 | const args = program.args 16 | 17 | if (args < 1) { 18 | console.error('Usage: [wasm file]') 19 | process.exit(1) 20 | } 21 | 22 | const content = await fsPromise.readFile(args[0]) 23 | const buffer = new Uint8Array(content).buffer 24 | const diswasm = new DisWasm(buffer, opts) 25 | try { 26 | diswasm.dump() 27 | } catch (e) { 28 | console.error(e) 29 | process.exit(1) 30 | } 31 | } 32 | 33 | main(process.argv) 34 | -------------------------------------------------------------------------------- /tool/find-riscv-toolchain: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if which riscv64-elf-gcc > /dev/null; then 4 | echo "riscv64-elf" 5 | elif which riscv64-unknown-elf-gcc > /dev/null; then 6 | echo "riscv64-unknown-elf" 7 | elif which riscv64-unknown-linux-gnu-gcc > /dev/null; then 8 | echo "riscv64-unknown-linux-gnu" 9 | else 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /tool/pack_libs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const {assert} = require('console') 4 | const fsPromise = require('fs').promises 5 | const {zip} = require('fflate') 6 | 7 | function isBinFile(fileName) { 8 | return fileName.match(/\.(wasm|a)$/) != null 9 | } 10 | 11 | function replaceRelativeInclude(content) { 12 | return content.replace(/^(#include\s+)"\..+\/([\w\d\-_.]+)"$/gm, '$1"$2"') 13 | } 14 | 15 | async function readFile(path) { 16 | if (isBinFile(path)) { 17 | return await fsPromise.readFile(path) 18 | } else { 19 | const text = await fsPromise.readFile(path, 'utf8') 20 | return replaceRelativeInclude(text) 21 | } 22 | } 23 | 24 | async function collectFiles(json) { 25 | switch (typeof json) { 26 | case 'string': 27 | return await readFile(json) 28 | case 'object': 29 | if (Array.isArray(json)) { 30 | const contents = await Promise.all(json.map((fn) => readFile(fn))) 31 | return contents.join('\n') 32 | } else { 33 | const files = {} 34 | await Promise.all(Object.keys(json).map(async key => { 35 | let result = await collectFiles(json[key]) 36 | if (result != null) { 37 | if (typeof result === 'string') { 38 | // Convert to Uint8Array. 39 | result = new TextEncoder().encode(result) 40 | } 41 | files[key] = result 42 | } 43 | })) 44 | return files 45 | } 46 | break 47 | default: 48 | assert(false) 49 | break 50 | } 51 | return null 52 | } 53 | 54 | async function main() { 55 | const argv = process.argv 56 | if (argv.length < 4) { 57 | console.error('argv < 4') 58 | process.exit(1) 59 | } 60 | 61 | const fn = argv[2] 62 | const dstfn = argv[3] 63 | 64 | const content = await fsPromise.readFile(fn, 'utf8') 65 | const json = JSON.parse(content) 66 | const files = await collectFiles(json) 67 | zip(files, {level: 9}, async (err, data) => { 68 | if (err) { 69 | console.error(err) 70 | process.exit(1) 71 | } 72 | await fsPromise.writeFile(dstfn, data) 73 | }) 74 | } 75 | 76 | main() 77 | -------------------------------------------------------------------------------- /tool/run-gen2wcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | PRJROOT=$(cd "$(dirname "$0")/..";pwd) 6 | WCCWASM=$PRJROOT/cc.wasm 7 | 8 | if [ ! -e "$WCCWASM" ]; then 9 | echo "Run 'make wcc-gen2' command to create executable" 1>&2 10 | exit 1 11 | fi 12 | 13 | "$PRJROOT/tool/runwasi" \ 14 | --dir=. \ 15 | --dir=/tmp \ 16 | "--mapdir=/usr/include::$PRJROOT/include" \ 17 | "--mapdir=/usr/lib::$PRJROOT/lib" \ 18 | "$WCCWASM" -- "$@" 19 | -------------------------------------------------------------------------------- /tool/run-riscv64: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | spike pk "$@" 6 | -------------------------------------------------------------------------------- /tool/runwasi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Before v20, node.js requires `--experimental-wasm-eh` option, but v20 raise error. 4 | # so check node.js whether the option is available or not. 5 | 6 | OPTION='--experimental-wasm-eh' 7 | node ${OPTION} --version > /dev/null 2>&1 8 | exitcode="$?" 9 | 10 | option=''; 11 | if [ "$exitcode" -eq 0 ]; then 12 | option="${OPTION}" 13 | fi 14 | 15 | CURRENT=$(cd "$(dirname "$0")";pwd) 16 | node ${option} --no-warnings=ExperimentalWarning "${CURRENT}/runwasi.js" "$@" 17 | exit "$?" 18 | -------------------------------------------------------------------------------- /tool/runwasi.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | 'use strict' 4 | 5 | const fsPromises = require('fs').promises 6 | const { WASI } = require('wasi') 7 | 8 | async function getRealpaths(map) { 9 | const promises = Object.keys(map).map(async key => { 10 | try { 11 | map[key] = await fsPromises.realpath(map[key]) 12 | } catch (e) { 13 | if (e.code === 'ENOENT') { 14 | console.error(`Error: "${map[key]}" not exist`) 15 | } else { 16 | console.error(e) 17 | } 18 | process.exit(1) 19 | } 20 | }) 21 | await Promise.all(promises) 22 | return map 23 | } 24 | 25 | ;(async () => { 26 | const preopens = {} 27 | function handleDir(value) { 28 | preopens[value] = value 29 | } 30 | function handleMapDir(value) { 31 | const [virt, actual] = value.split('::', 2) 32 | preopens[virt] = actual 33 | } 34 | 35 | const {program} = require('commander') 36 | program 37 | .option('--dir ', 'Make a directory accessible', handleDir) 38 | .option('--mapdir ', 'Map actual as virtual path', handleMapDir) 39 | .allowExcessArguments() 40 | .parse(process.argv) 41 | .usage('[.wasm] ') 42 | 43 | if (program.args.length <= 0) { 44 | program.help() 45 | process.exit(1) 46 | } 47 | 48 | const wasmFileName = program.args[0] 49 | const wasi = new WASI({ 50 | version: 'preview1', 51 | args: program.args, 52 | env: process.env, 53 | preopens: await getRealpaths(preopens), 54 | }) 55 | 56 | try { 57 | const wasmBin = await fsPromises.readFile(wasmFileName) 58 | const wasmModule = await WebAssembly.compile(wasmBin) 59 | const importObject = wasi.getImportObject?.call(wasi) ?? 60 | { wasi_snapshot_preview1: wasi.wasiImport } 61 | const instance = await WebAssembly.instantiate(wasmModule, importObject) 62 | const result = wasi.start(instance) 63 | process.exit(result) 64 | } catch (e) { 65 | console.error(e) 66 | process.exit(1) 67 | } 68 | })() 69 | -------------------------------------------------------------------------------- /tool/xccsh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xcc=$(cd "$(dirname "$0")/..";pwd)/xcc 4 | 5 | UNAME=$(uname) 6 | ARCH=$(arch) 7 | 8 | if [[ "$UNAME" = "Darwin" ]]; then 9 | SYS_INCLUDE_DIR="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include" 10 | else 11 | SYS_INCLUDE_DIR="/usr/include/$ARCH-linux-gnu" 12 | fi 13 | 14 | xcc_opt="\ 15 | -fuse-ld=cc -no-pie \ 16 | -isystem /usr/include \ 17 | -isystem /usr/local/include \ 18 | -isystem $SYS_INCLUDE_DIR \ 19 | -D__signed__=" 20 | 21 | CC="$xcc $xcc_opt -D_GNU_SOURCE" 22 | 23 | $CC "$@" 24 | -------------------------------------------------------------------------------- /vite.config.mts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | base: './', 6 | root: 'src/wcc/www', 7 | publicDir: '../../../public', 8 | build: { 9 | outDir: resolve(__dirname, 'release'), 10 | rollupOptions: { 11 | output: { 12 | entryFileNames: '[name].js', 13 | assetFileNames: '[name].[ext]', 14 | }, 15 | }, 16 | assetsInlineLimit: 8192, 17 | }, 18 | worker: { 19 | rollupOptions: { 20 | output: { 21 | entryFileNames: '[name].js', 22 | assetFileNames: '[name].[ext]', 23 | }, 24 | }, 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /wcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tyfkda/xcc/8c478ea28aaffb8b4bbf1d1320acaa6ebbe41662/wcc.png --------------------------------------------------------------------------------