boot4.sh (6400B)
1 #!/bin/sh 2 ## boot4.sh — self-host tcc rebuild stages on top of boot3's tcc0. 3 ## 4 ## boot3 produced tcc0 (cc.scm-built bootstrap). boot4 runs the rest of 5 ## the four-stage chain: tcc0 → tcc1 → tcc2 → tcc3. The bootstrap 6 ## fixed-point check is `tcc2 == tcc3`: once tcc is compiling itself 7 ## with no help from cc.scm, the chain reaches a byte-identical fixed 8 ## point. (See docs/PLAN.md for the cc.scm vs tcc codegen-divergence 9 ## reasoning behind needing four stages rather than two.) 10 ## 11 ## tcc0 = tcc-source compiled by cc.scm ← boot3 12 ## tcc1 = tcc-source compiled by tcc0 ← produced here 13 ## tcc2 = tcc-source compiled by tcc1 ← produced here 14 ## tcc3 = tcc-source compiled by tcc2 ← produced here 15 ## 16 ## ─── Inputs (sources, from canonical tree) ─────────────────────────── 17 ## build/$ARCH/src/src/tcc-libc/$ARCH/{start.S, sys_stubs.S} 18 ## build/$ARCH/src/src/tcc-cc/mem.c 19 ## build/$ARCH/src/src/tcc/tcc-0.9.26-1147-gee75a10c/lib/<arch-specific> 20 ## build/$ARCH/src/src/tcc/tcc.flat.c 21 ## build/$ARCH/src/src/libc/libc.flat.c 22 ## build/$ARCH/src/src/test-fixtures/boot-hello.c 23 ## 24 ## ─── Inputs (binaries from prior stages) ────────────────────────────── 25 ## build/$ARCH/$DRIVER/boot3/tcc0 26 ## build/$ARCH/$DRIVER/boot2/{catm, scheme1} 27 ## 28 ## ─── Tools ──────────────────────────────────────────────────────────── 29 ## scheme1 evaluates a host-generated run.scm (from boot4-gen-runscm.sh) 30 ## against the flat staging root. Every arch has CONFIG_TCC_ASM and 31 ## assembles .S inputs (start.S, sys_stubs.S) directly inside the 32 ## container; no host asm step. The aarch64 assembler is the phase-1 33 ## arm64-asm.c that flatten patches into tcc-0.9.26 (see 34 ## docs/TCC-ARM64-ASM.md). 35 ## 36 ## ─── Outputs ────────────────────────────────────────────────────────── 37 ## build/$ARCH/$DRIVER/boot4/{tcc1, tcc2, tcc3} 38 ## tcc2 and tcc3 are byte-identical (asserted 39 ## below) — that equality is the fixed-point. 40 ## build/$ARCH/$DRIVER/boot4/crt1.o 41 ## tcc2-built startup object, kept outside 42 ## libc.a because it must lead link lines. 43 ## build/$ARCH/$DRIVER/boot4/libc.a 44 ## tcc2-built archive of sys_stubs.o + mem.o 45 ## + libc.o 46 ## build/$ARCH/$DRIVER/boot4/libtcc1.a 47 ## tcc2-built tcc compiler helper archive 48 ## build/$ARCH/$DRIVER/boot4/hello — mes-libc-linked smoke binary 49 ## 50 ## ─── Env knobs ──────────────────────────────────────────────────────── 51 ## TCC_BOOTSTRAP_RELAX_FIXEDPOINT=1 52 ## After a codegen-altering tcc patch, the two-stage rule needs a 53 ## third bounce to converge. Set this to accept tcc3 even when 54 ## tcc2 != tcc3; the next boot4 run, started from this run's 55 ## tcc3, will reach tcc2 == tcc3 with no extra knob. 56 ## 57 ## Usage: scripts/boot4.sh <arch> 58 ## <arch> ∈ {aarch64, amd64, riscv64} for either DRIVER (default podman). 59 60 set -eu 61 62 . scripts/lib-arch.sh 63 bootlib_init boot4 "${1:-}" 64 driver_init empty 65 require_src 66 67 case "$ARCH" in 68 aarch64) LIBTCC1_C_SRCS="lib-arm64.c"; LIBTCC1_ASM_SRCS="" ;; 69 amd64) LIBTCC1_C_SRCS="libtcc1.c va_list.c"; LIBTCC1_ASM_SRCS="alloca86_64.S alloca86_64-bt.S" ;; 70 riscv64) LIBTCC1_C_SRCS="lib-arm64.c"; LIBTCC1_ASM_SRCS="" ;; 71 esac 72 73 BOOT2=build/$ARCH/$DRIVER/boot2 74 BOOT3=build/$ARCH/$DRIVER/boot3 75 SRC=build/$ARCH/src 76 77 TCC_PKG=tcc-0.9.26-1147-gee75a10c 78 TCC_LIB_REL=tcc/$TCC_PKG/lib 79 80 # ── prerequisites ───────────────────────────────────────────────────── 81 require_prev "$BOOT3" tcc0 82 require_prev "$BOOT2" catm scheme1 83 for f in $LIBTCC1_C_SRCS $LIBTCC1_ASM_SRCS; do 84 require_file "$SRC/src/$TCC_LIB_REL/$f" 85 done 86 87 # ── stage inputs and run scheme1 + boot4 run.scm under $DRIVER ──────── 88 . scripts/lib-runscm.sh 89 runscm_init "$STAGE" "$OUT" 90 runscm_gen scripts/boot4-gen-runscm.sh "$ARCH" 91 92 runscm_scheme1 "$BOOT2/scheme1" 93 runscm_prelude "$SRC/src/scheme1/prelude.scm" 94 95 runscm_input tcc0 "$BOOT3/tcc0" 96 runscm_input catm "$BOOT2/catm" 97 98 runscm_input_from_src "tcc-libc/$ARCH/start.S" 99 runscm_input_from_src "tcc-libc/$ARCH/sys_stubs.S" 100 runscm_input_from_src tcc-cc/mem.c 101 for f in $LIBTCC1_C_SRCS $LIBTCC1_ASM_SRCS; do 102 runscm_input_from_src "$TCC_LIB_REL/$f" 103 done 104 105 runscm_input_from_src tcc/tcc.flat.c 106 runscm_input_from_src libc/libc.flat.c 107 runscm_input_from_src test-fixtures/boot-hello.c hello.c 108 109 runscm_export tcc1 tcc2 tcc3 s3-crt1.o s3-libc.a s3-libtcc1.a hello 110 runscm_run "${BOOT4_TIMEOUT:-5400}" 111 112 # ── fixed-point check (host-side) ───────────────────────────────────── 113 if ! cmp -s "$OUT/tcc2" "$OUT/tcc3"; then 114 s2=$(wc -c <"$OUT/tcc2") 115 s3=$(wc -c <"$OUT/tcc3") 116 if [ "${TCC_BOOTSTRAP_RELAX_FIXEDPOINT:-0}" = 1 ]; then 117 echo "[$BOOT_TAG] WARN: tcc2 ($s2) != tcc3 ($s3); TCC_BOOTSTRAP_RELAX_FIXEDPOINT=1, accepting tcc3" >&2 118 else 119 echo "[$BOOT_TAG] FIXED-POINT FAIL: tcc2 ($s2) != tcc3 ($s3)" >&2 120 exit 1 121 fi 122 fi 123 124 # ── normalize output names (drop s3- prefix) ────────────────────────── 125 # tcc1 / tcc2 are kept on disk: the test path (tcc-cc / tcc-libc suites) 126 # uses them as stage-2 / stage-3 self-built tcc binaries. 127 mv "$OUT/s3-crt1.o" "$OUT/crt1.o" 128 mv "$OUT/s3-libc.a" "$OUT/libc.a" 129 mv "$OUT/s3-libtcc1.a" "$OUT/libtcc1.a" 130 chmod 0700 "$OUT/tcc1" "$OUT/tcc2" "$OUT/tcc3" "$OUT/hello" 131 132 echo "[$BOOT_TAG] sizes: libtcc1.a=$(wc -c <"$OUT/libtcc1.a") libc.a=$(wc -c <"$OUT/libc.a") hello=$(wc -c <"$OUT/hello")" 133 echo "[$BOOT_TAG] OK -> $OUT/{tcc3, crt1.o, libc.a, libtcc1.a, hello} (fixed point: tcc2 == tcc3)"