commit 7b5e7555d188cf472b3cc976fe9e822bfe44bc56
parent 2f64feff1b6fae46b89935446c0c27a90d6fa0f4
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 12:09:07 -0700
test/cross: pin freestanding-rv32 corpus to ilp32f (match bare harness)
The bare-metal rv32 cross harness (test/lib/exec_bare.sh) builds its reset
stub + runtime hard-single (ilp32f, ELF e_flags 0x3), but the smoke/coarse
lanes compiled corpus cases with no -mabi. Commit b436d6ef flipped kit's rv32
default from ilp32f to soft-float (ilp32, e_flags 0x1), so the corpus objects
regressed to 0x1 and the freestanding link's cross-input ABI guard rejected
them ("incompatible ELF e_flags (0x1 vs 0x3)").
Pin both -ffreestanding compile sites to the harness ABI via a
freestanding_abi_flags helper (rv32 -> -march=rv32imafc_zicsr_zifencei
-mabi=ilp32f, empty for every other arch), mirroring what test/toy/run.sh and
test/smoke/rv32.sh already do. The compiler default-flip is intentional; only
the cross harness was implicitly relying on it.
Verified: freestanding-rv32 smoke 3/3 and coarse 7/7 (cc+ld+qemu run); all
freestanding targets smoke 15/15 (no regression on aa64/x64/rv64/arm32).
Diffstat:
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/scripts/cross_test.sh b/scripts/cross_test.sh
@@ -68,6 +68,20 @@ tok_os() { printf '%s' "${1%%-*}"; }
tok_arch() { printf '%s' "${1##*-}"; }
tok_libc() { case "$1" in linux-*) local r="${1#linux-}"; printf '%s' "${r%%-*}" ;; *) printf '' ;; esac; }
+# Per-arch -march/-mabi a freestanding corpus object must be compiled with so
+# its ELF e_flags match the bare-metal stub + runtime it is linked against
+# (test/lib/exec_bare.sh). rv32 is the one with a float-ABI axis: the bare
+# harness (and the toy cross lane) are hard-single (ilp32f), but kit's rv32
+# *default* is now soft-float (ilp32, commit b436d6ef) — without pinning, the
+# corpus object's e_flags (0x1) mismatch the stub's (0x3) and the freestanding
+# link rejects it. Keep in sync with _bare_emit_rv32 / test/toy/run.sh.
+freestanding_abi_flags() { # token -> echoes extra cc flags ("" for most arches)
+ case "$(tok_arch "$1")" in
+ rv32) printf '%s' "-march=rv32imafc_zicsr_zifencei -mabi=ilp32f" ;;
+ *) printf '' ;;
+ esac
+}
+
# Link modes to smoke per target. musl exercises BOTH static (libc.a) and
# dynamic (libc.so) — the two ways the sysroot is consumed. freebsd is static
# (self-contained base). Everything else uses the toolchain default (one mode;
@@ -168,7 +182,8 @@ coarse_build_token() {
local fobj="$cdir/c_frontback_amalgam.${opt}.o"
local out="$cdir/c_frontback_amalgam.${opt}.out"
local err="$cdir/c_frontback_amalgam.${opt}.err"
- if ! "$HOSTED" cc "$t" -$opt -ffreestanding -c "$CASES/c_frontback_amalgam.c" -o "$fobj" \
+ # shellcheck disable=SC2046
+ if ! "$HOSTED" cc "$t" -$opt $(freestanding_abi_flags "$t") -ffreestanding -c "$CASES/c_frontback_amalgam.c" -o "$fobj" \
>"$cdir/c_frontback_amalgam.$opt.cc.out" 2>"$cdir/c_frontback_amalgam.$opt.cc.err"; then
kit_fail "frontback_amalgam/$t:$opt:cc" "cc failed"; sed 's/^/ | /' "$cdir/c_frontback_amalgam.$opt.cc.err" | head; return
fi
@@ -223,7 +238,8 @@ smoke_build_case() {
# Every freestanding arch (arm32 included, since Phase 2 landed the -O1
# known-frame path) exercises the optimizer at -O1.
smopt=O1
- if ! "$HOSTED" cc "$t" -$smopt -ffreestanding -c "$src" -o "$obj" \
+ # shellcheck disable=SC2046
+ if ! "$HOSTED" cc "$t" -$smopt $(freestanding_abi_flags "$t") -ffreestanding -c "$src" -o "$obj" \
>"$cdir/$name.cc.out" 2>"$cdir/$name.cc.err"; then
kit_fail "$label:cc" "cc failed"; sed 's/^/ | /' "$cdir/$name.cc.err" | head; return
fi