boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 5a7810a26c913cc58cc897e93e2de2f64b8d6a01
parent f86b3b6be24d5cfedceb4fb18bf379235a95ee73
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 30 Apr 2026 06:29:38 -0700

Add tcc-cc test suite

Diffstat:
MMakefile | 35+++++++++++++++++++++++++++++++----
Mdocs/TCC-TODO.md | 4++--
Mscripts/boot-run-tests.sh | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mscripts/run-tests.sh | 5+++--
Mscripts/stage1-flatten.sh | 15++++++++-------
Atcc-cc/aarch64/start.S | 7+++++++
6 files changed, 123 insertions(+), 17 deletions(-)

diff --git a/Makefile b/Makefile @@ -24,6 +24,7 @@ # make test SUITE=m1pp m1pp suite, every arch # make test SUITE=p1 ARCH=amd64 p1 suite, one arch # make test SUITE=scheme1 scheme1 .scm fixtures, every arch +# make test SUITE=tcc-cc tcc-boot2 compiles tests/cc, aarch64 # make image build the per-arch container image # make tools bootstrap M0/hex2-0/catm for ARCH # make tables regen pre-pruned P1/P1-<arch>.M1 tables @@ -212,9 +213,10 @@ $(CC_BINS): build/%/cc/cc.scm: $(CC_SRCS) build/%/.image build/%/tools/M0 # the per-arch container against the flattened TU, then assembles the # resulting P1pp into a runnable ELF using the standard P1pp pipeline. # The resulting binary embeds tcc's $(TCC_TARGET) codegen, so match -# $(ARCH) to it (amd64↔X86_64, riscv64↔RISCV64) if you want to run the -# binary natively in the container. tcc.flat.c lives outside the per- -# arch tree because it depends on TCC_TARGET, not the build arch. +# $(ARCH) to it (aarch64↔ARM64, amd64↔X86_64, riscv64↔RISCV64) if you +# want generated programs to run natively in the container. tcc.flat.c +# lives outside the per-arch tree because it depends on TCC_TARGET, not +# the build arch. TCC_TARGET ?= X86_64 TCC_FLAT := build/tcc/$(TCC_TARGET)/tcc.flat.c @@ -318,6 +320,21 @@ $(TCC_GCC_BIN): $(TCC_FLAT) build/$(TCC_GCC_ARCH)/vendor/mes-libc/libc.flat.c \ sh scripts/build-tcc-gcc.sh $@ $(TCC_FLAT) \ build/$(TCC_GCC_ARCH)/vendor/mes-libc/libc.flat.c +# --- tcc-cc test harness support ----------------------------------------- +# +# The ARM64-targeted tcc-boot2 can compile/link tests/cc directly, but +# its ARM64 build does not accept .S inputs yet. Build the one tiny +# _start object with the host cross assembler, then let tcc link it +# with each test fixture under the tcc-cc suite. + +HOST_CC ?= cc +TCC_CC_ARCH := aarch64 +TCC_CC_START := build/$(TCC_CC_ARCH)/tcc-cc/start.o + +$(TCC_CC_START): tcc-cc/$(TCC_CC_ARCH)/start.S + mkdir -p $(@D) + $(HOST_CC) -target aarch64-linux-gnu -c -o $@ -x assembler $< + # --- Native tools (opt-in dev-loop helpers) ------------------------------- NATIVE_TOOLS := build/native-tools/M1 build/native-tools/hex2 build/native-tools/m1pp @@ -387,6 +404,10 @@ TEST_CC_LIBC_DEPS := $(TEST_CC_DEPS) \ $(foreach a,$(TEST_ARCHES),build/$(a)/vendor/mes-libc/libc.P1pp) \ P1/entry-libc.P1pp P1/elf-end.P1pp +TEST_TCC_CC_DEPS := build/$(TCC_CC_ARCH)/.image \ + build/$(TCC_CC_ARCH)/tcc-boot2/tcc-boot2 \ + $(TCC_CC_START) + test: ifeq ($(SUITE),) @$(MAKE) --no-print-directory test SUITE=m1pp @@ -416,6 +437,12 @@ else ifeq ($(SUITE),cc) else ifeq ($(SUITE),cc-libc) @$(MAKE) --no-print-directory $(TEST_CC_LIBC_DEPS) sh scripts/run-tests.sh --suite=cc-libc $(if $(ARCH_FILTER),--arch=$(ARCH_FILTER)) $(NAMES) +else ifeq ($(SUITE),tcc-cc) + @if [ -n "$(ARCH_FILTER)" ] && [ "$(ARCH_FILTER)" != "$(TCC_CC_ARCH)" ]; then \ + echo "tcc-cc currently supports ARCH=$(TCC_CC_ARCH) only" >&2; exit 2; \ + fi + @$(MAKE) --no-print-directory TCC_TARGET=ARM64 $(TEST_TCC_CC_DEPS) + sh scripts/run-tests.sh --suite=tcc-cc --arch=$(TCC_CC_ARCH) $(NAMES) else - @echo "unknown SUITE='$(SUITE)' (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc)" >&2; exit 2 + @echo "unknown SUITE='$(SUITE)' (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc | tcc-cc)" >&2; exit 2 endif diff --git a/docs/TCC-TODO.md b/docs/TCC-TODO.md @@ -120,8 +120,8 @@ Harness target: `make tcc-boot2 ARCH=aarch64` (see Makefile + cc.scm on the flattened TU inside the container, and feeds the P1pp into the standard `boot-build-p1pp.sh` pipeline. `TCC_TARGET` selects which tcc codegen target gets baked into the binary -(default `X86_64`); pick `ARCH` to match if you want the result to -run natively in the per-arch container. +(default `X86_64`; use `ARM64` for aarch64); pick `ARCH` to match if +you want generated programs to run natively in the per-arch container. ## Resolved — offsetof-style const expr in `options_W[]` (line 18026) diff --git a/scripts/boot-run-tests.sh b/scripts/boot-run-tests.sh @@ -14,7 +14,7 @@ ## host preflights lint and passes the explicit kept list down. ## ## Env: ARCH=aarch64|amd64|riscv64 -## Usage: boot-run-tests.sh --suite=<m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc> [name ...] +## Usage: boot-run-tests.sh --suite=<m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc|tcc-cc> [name ...] set -eu @@ -35,7 +35,7 @@ while [ "$#" -gt 0 ]; do done case "$SUITE" in - m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc) ;; + m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc|tcc-cc) ;; "") echo "$0: --suite required" >&2; exit 2 ;; *) echo "$0: unknown suite '$SUITE'" >&2; exit 2 ;; esac @@ -501,6 +501,75 @@ run_cc_libc_suite() { done } +## --- tcc-cc suite ------------------------------------------------------- +## +## Runs the plain tests/cc fixtures through the tcc-boot2 binary. The +## Makefile builds tcc-boot2 with TCC_TARGET=ARM64 and supplies a tiny +## aarch64 _start object at build/aarch64/tcc-cc/start.o, so this suite +## can link and execute non-libc C tests directly on the target arch. +run_tcc_cc_suite() { + if [ "$ARCH" != "aarch64" ]; then + echo " FAIL [$ARCH] tcc-cc" + echo " tcc-cc currently supports ARCH=aarch64 only" >&2 + return + fi + + tcc=build/$ARCH/tcc-boot2/tcc-boot2 + start=build/$ARCH/tcc-cc/start.o + if [ ! -x "$tcc" ]; then + echo " FAIL [$ARCH] tcc-cc" + echo " missing $tcc -- run 'make test SUITE=tcc-cc ARCH=$ARCH'" >&2 + return + fi + if [ ! -e "$start" ]; then + echo " FAIL [$ARCH] tcc-cc" + echo " missing $start -- run 'make test SUITE=tcc-cc ARCH=$ARCH'" >&2 + return + fi + if ! "$tcc" -version 2>/dev/null | grep 'AArch64' >/dev/null; then + echo " FAIL [$ARCH] tcc-cc" + echo " $tcc is not an AArch64-targeted tcc; rebuild with TCC_TARGET=ARM64" >&2 + return + fi + + [ -n "$NAMES" ] || NAMES=$(discover tests/cc c) + for name in $NAMES; do + src=tests/cc/$name.c + [ -e "$src" ] || { echo " SKIP $name (no .c)"; continue; } + if [ -e tests/cc/$name.expected ]; then + expout=$(cat tests/cc/$name.expected) + else + expout= + fi + if [ -e tests/cc/$name.expected-exit ]; then + expexit=$(cat tests/cc/$name.expected-exit) + else + expexit=0 + fi + + elf=build/$ARCH/tests/tcc-cc/$name + workdir=build/$ARCH/.work/tests/tcc-cc/$name + label="[$ARCH] tcc-cc/$name" + mkdir -p "$(dirname "$elf")" "$workdir" + + tcc_log=$workdir/tcc.log + if ! "$tcc" -nostdlib "$start" "$src" -o "$elf" \ + >"$tcc_log" 2>&1; then + fail "$label" "tcc compile/link failed:" "$tcc_log" + continue + fi + + tmp=$(mktemp) + if "./$elf" >"$tmp" 2>&1; then + act_exit=0 + else + act_exit=$? + fi + act_out=$(cat "$tmp"); rm -f "$tmp" + _cc_check "$label" "$expout" "$expexit" "$act_out" "$act_exit" + done +} + case "$SUITE" in m1pp) run_m1pp_suite ;; p1) run_p1_suite ;; @@ -511,4 +580,5 @@ case "$SUITE" in cc-cg) run_cc_cg_suite ;; cc) run_cc_suite ;; cc-libc) run_cc_libc_suite ;; + tcc-cc) run_tcc_cc_suite ;; esac diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh @@ -25,6 +25,7 @@ ## cc-pp tests/cc-pp/<name>.c — pp pipeline byte-diff (+ .scm). ## cc-cg tests/cc-cg/<name>.scm — cg emit -> P1pp -> ELF -> run. ## cc tests/cc/<name>.c — cc -> P1pp -> ELF -> run. +## tcc-cc tests/cc/<name>.c — tcc-boot2 -> ELF -> run. ## ## All three arches by default; --arch restricts to one. ## @@ -50,8 +51,8 @@ while [ "$#" -gt 0 ]; do done case "$SUITE" in - m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc) ;; - "") echo "$0: --suite required (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc)" >&2; exit 2 ;; + m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc|tcc-cc) ;; + "") echo "$0: --suite required (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc | tcc-cc)" >&2; exit 2 ;; *) echo "$0: unknown suite '$SUITE'" >&2; exit 2 ;; esac diff --git a/scripts/stage1-flatten.sh b/scripts/stage1-flatten.sh @@ -17,7 +17,7 @@ ## artifact downstream stages consume. No container needed. ## ## Usage: -## scripts/stage1-flatten.sh [--arch <X86_64|I386|RISCV64>] [--verify] +## scripts/stage1-flatten.sh [--arch <X86_64|I386|RISCV64|ARM64|AARCH64>] [--verify] set -eu @@ -34,10 +34,11 @@ while [ $# -gt 0 ]; do done case "$ARCH" in - X86_64) MES_ARCH=x86_64; HAVE_LL=1 ;; - I386) MES_ARCH=x86; HAVE_LL=0 ;; - RISCV64) MES_ARCH=riscv64; HAVE_LL=1 ;; - AARCH64) echo "AARCH64 not in live-bootstrap; tcc.c lacks an arm64-gen.c" >&2; exit 2 ;; + X86_64|x86_64) MES_ARCH=x86_64; HAVE_LL=1; TCC_TARGET_DEFINE=X86_64; CPP_ARCH=x86_64 ;; + I386|i386) MES_ARCH=x86; HAVE_LL=0; TCC_TARGET_DEFINE=I386; CPP_ARCH=x86 ;; + RISCV64|riscv64) MES_ARCH=riscv64; HAVE_LL=1; TCC_TARGET_DEFINE=RISCV64; CPP_ARCH=riscv64 ;; + ARM64|arm64|AARCH64|aarch64) + MES_ARCH=riscv64; HAVE_LL=1; TCC_TARGET_DEFINE=ARM64; CPP_ARCH=aarch64 ;; *) echo "unknown ARCH: $ARCH" >&2; exit 2 ;; esac @@ -157,7 +158,7 @@ FLAT=$WORK/tcc.flat.c -I "$MES_INCLUDE_LINUX" \ -I "$MES_INCLUDE" \ -D __linux__=1 \ - -D __${MES_ARCH}__=1 \ + -D __${CPP_ARCH}__=1 \ -D BOOTSTRAP=1 \ -D HAVE_LONG_LONG=$HAVE_LL \ -D inline= \ @@ -173,7 +174,7 @@ FLAT=$WORK/tcc.flat.c -D CONFIG_USE_LIBGCC=1 \ -D "TCC_VERSION=\"0.9.26\"" \ -D ONE_SOURCE=1 \ - -D TCC_TARGET_${ARCH}=1 \ + -D TCC_TARGET_${TCC_TARGET_DEFINE}=1 \ "$SRC/tcc.c" > "$FLAT" LINES=$(wc -l < "$FLAT") diff --git a/tcc-cc/aarch64/start.S b/tcc-cc/aarch64/start.S @@ -0,0 +1,7 @@ +.globl _start +_start: + ldr x0, [sp] + add x1, sp, #8 + bl main + mov x8, #93 + svc #0