Kit0 integration
boot2 can compile a prepared Kit bootstrap profile as separate translation
units and link the resulting P1pp through its ordinary per-architecture
P1/M1pp/hex2pp path. The supported boot2 architecture names are aarch64,
amd64, and riscv64; RV32 has no corresponding Kit0 profile. Kit currently
supplies the aa64 preparation; the x64 and rv64 mappings are ready for
the corresponding profiles when they are added.
Prepare and check from the Kit worktree:
cd ../../kit
gmake bootstrap-aa64-prepare
KIT0_SWEEP_JOBS=2 gmake bootstrap-aa64-check
Or run only the boot2 link from this worktree:
gmake ARCH=aarch64 DRIVER=podman \
KIT0_PREP="$(cd ../../kit && pwd)/build/bootstrap-aa64/kit0-prep" kit0
podman run --rm --pull=never --platform linux/arm64 \
-v "$(pwd):/boot2" -w /boot2 boot2-busybox-test:aarch64 \
/boot2/build/aarch64/podman/kit0/kit0 --version
When KIT0_PREP is omitted, the Makefile maps boot2 architecture names to the
conventional Kit profile suffixes: aarch64 to aa64, amd64 to x64, and
riscv64 to rv64. KIT_DIR defaults to ../../kit, KIT0_PROFILE can
override just the profile suffix, and an explicit KIT0_PREP can point
anywhere. The selected preparation must enable the matching
KIT_ARCH_*_ENABLED setting in resolved-config.h; this prevents accidentally
framing, assembling, or running one target's prepared sources as another
target.
boot/kit0.sh validates the prepared manifest.tsv, resolved-config.h, and
m1pp-partitions.tsv, then imports the preprocessed tu/*.i files and
kit0-run.scm. The partition manifest is the inspectable record of the order
encoded in that recipe. The recipe compiles mes-libc and each Kit TU
separately. It expands the M1pp runtime
once, then independently expands entry, libc, every Kit TU, and the ELF
terminator by replaying the common macro prelude and using %reset-output
with disjoint hygiene-label ranges. Each non-runtime partition begins with
.align 16. The ordered hex2pp partitions are concatenated, prefixed with
the ELF framing, and assembled by the existing hex2pp stage. It does not copy
generated Kit inputs into this worktree.
General cc.scm additions
Kit0 exposed a few ordinary C gaps. They are implemented without Kit source or filename special cases:
_Noreturn, checked_Static_assert,_Alignof(plus GNU aliases), and layout-neutral_Alignas; motivated by Kit's public/config/core headers.- File-scope unevaluated
sizeof/alignment designators, array/nested-field designators, and aggregate compound literals in global initializers; motivated by Kit's source tables andKIT_SLICE_LIT-style initializers. __builtin_offsetofover member/constant-subscript designators in both integer-constant and ordinary expression contexts, motivated by Kit's aggregate-layout assertions and container recovery inlink_script.c.- By-value calls for aggregates wider than two target words, implemented as a caller-owned copy passed through an invisible pointer; motivated by Kit's context/option structures. Direct aggregate arguments are addressed and copied correctly even when the source is an indirect member lvalue.
- Unsigned one-word division and remainder, carried as distinct
UDIVandUREMP1 operations on every backend rather than inheriting signedDIVandREMbehavior. - Local nested aggregate initialization distinguishes a compatible whole-aggregate assignment expression from brace elision, including designated compound literals.
- Unevaluated-expression snapshots restore frame allocation, indirect-slot,
label, outgoing-call, emission-buffer, and value-stack state, so
sizeofcannot alter a later local's storage. - An immediate string literal retains its array bound under
sizeof, making localKIT_SLICE_LITlengths agree with their file-scope equivalents. - Block-scope static objects use a per-function declaration identity in their
emitted label. Distinct lexical
ordertables no longer collapse merely because they share a source spelling. - Complete
--libtranslation-unit namespacing for static objects/functions, strings, frame slots, user labels, and generated labels. This makes P1pp fragments independently compilable and safely concatenable. - A 512 KiB reusable per-function emission buffer on 64-bit targets, sized for Kit's largest linker-layout routine while preserving cc.scm's fixed-allocation model and RV32's existing 256 KiB heap budget.
- A 32-word variadic receive window (with ABI-word-aware bounds checks), covering Kit's 20-argument linker diagnostics without changing the existing four-register/stack-argument convention.
The intentionally bootstrap-level behavior is documented in docs/CC.md:
_Noreturn carries no metadata, and _Alignas accepts only the universally
layout-neutral zero or one/char requests because P1's seed object layout
cannot represent over-alignment. Kit's prepared implementation TUs contain no
live _Alignas declarations; the focused fixture exercises this no-op
contract.
Focused regression tests
Run the compatibility cases across all four boot2 architectures:
tests/run.sh --suite cc \
320-vararg-cap 346-c11-decl-align 347-aggregate-indirect-arg \
348-unsigned-div-rem 349-aggregate-indirect-lvalue-arg \
350-large-aggregate-flow 351-address-of-member-local \
352-aggregate-compound-call 353-static-local-scope-collision
tests/run.sh --suite cc-util 015-lib-static-namespace
tests/run.sh --suite m1pp 032-reset-output
The first fixture exercises a 20-argument call above the former variadic
window. The declaration fixture covers every added declaration/alignment form
plus both offsetof contexts, nested designators, and grouped aggregate
compound initialization. The aggregate fixture checks that a callee may
mutate a large by-value argument without changing its source object. The
additional aggregate fixtures cover indirect member lvalues and nested
whole-aggregate flow. The arithmetic fixture checks unsigned quotient and
remainder boundary cases. The address fixture protects the unevaluated
snapshot invariant. The compound-call fixture checks both the two-word
argument shape and local string-literal sizeof; the static-local fixture
checks same-spelling declarations in distinct scopes. The utility fixture
checks every non-function-local label family under --lib; the M1pp fixture
checks output reset and hygiene-base selection.
The Kit-side check then supplies the integration coverage: every selected TU must translate, the entire P1 set must link with mes-libc, the resulting Kit0 must run for the selected architecture, and that seed-built compiler must emit and archive target objects and statically link a representative executable.