#!/usr/bin/env bash # buildGno.sh — compile a C or C++ source into a GNO/ME-loadable OMF # shell command. # # Usage: bash demos/buildGno.sh # demos/.c -> demos/.omf (compiled with clang) # demos/.cpp -> demos/.omf (compiled with clang++) # # Uses crt0Gno (GNO entry contract) + the GNO libc backend, then wraps # the flat image in a relocatable ExpressLoad OMF via omfEmit — the # GS/OS Loader (which GNO uses to launch commands) requires a real OMF, # not a flat binary. C++ programs additionally link libcxxabi.o # (operator new/delete/__cxa_atexit/__cxa_guard_*/dynamic_cast/typeinfo) # and libcxxabiSjlj.o (SJLJ exception runtime). Link-time GC removes # whichever portions aren't referenced, so the cost is zero for pure-C # programs. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" [ $# -ge 1 ] || { echo "usage: $0 " >&2; exit 2; } BASE="$1" if [ -f "$SCRIPT_DIR/$BASE.cpp" ]; then SRC="$SCRIPT_DIR/$BASE.cpp" CC="$ROOT/tools/llvm-mos-build/bin/clang++" LANG_FLAGS="-fno-exceptions -fno-rtti" elif [ -f "$SCRIPT_DIR/$BASE.c" ]; then SRC="$SCRIPT_DIR/$BASE.c" CC="$ROOT/tools/llvm-mos-build/bin/clang" LANG_FLAGS="" else echo "no source: $SCRIPT_DIR/$BASE.{c,cpp}" >&2 exit 2 fi LINK="$ROOT/tools/link816" OMF="$ROOT/tools/omfEmit" RT="$ROOT/runtime" OBJ="$SCRIPT_DIR/$BASE.o" BIN="$SCRIPT_DIR/$BASE.bin" MAP="$SCRIPT_DIR/$BASE.map" RELOC="$SCRIPT_DIR/$BASE.reloc" OUT="$SCRIPT_DIR/$BASE.omf" echo "compile: $(basename "$SRC") -> $BASE.o" # `-I include/c++` makes headers findable when the source is .cpp. # Harmless for .c — the directory just doesn't contain anything reachable # from a C TU. "$CC" --target=w65816 -I"$RT/include" -I"$RT/include/c++" -O2 -ffunction-sections $LANG_FLAGS -c "$SRC" -o "$OBJ" echo "link: -> $BASE.bin" "$LINK" -o "$BIN" --text-base 0x1000 --bss-base 0xA000 \ --map "$MAP" --reloc-out "$RELOC" \ "$RT/crt0Gno.o" "$OBJ" \ "$RT/libcGno.o" "$RT/gnoKernel.o" "$RT/gnoGsos.o" \ "$RT/libc.o" "$RT/snprintf.o" "$RT/extras.o" \ "$RT/softFloat.o" "$RT/softDouble.o" \ "$RT/libgcc.o" \ "$RT/libcxxabi.o" "$RT/libcxxabiSjlj.o" echo "OMF: -> $BASE.omf" # Declare a dedicated DP/Stack (OMF KIND=0x1012) segment. Without it GNO # falls back to a 4 KB default stack shared with DP and placed low in bank 0, # which is too small / mis-placed for GS/OS file I/O: GNO's GS/OS interceptor # (StackGSOS) carves its direct-page work area off the caller's S and the FST # nests deep below it, corrupting the saved SP on certain stack-buffer layouts. # A sized $12 segment makes the Loader allocate a larger bank-0 block (S set # high in it), giving headroom and moving stack buffers off the collision. # This is the idiomatic ORCA/GNO mechanism (== #pragma stacksize). "$OMF" --input "$BIN" --map "$MAP" \ --base 0x1000 --entry __start --output "$OUT" \ --name "$(echo "$BASE" | tr '[:lower:]' '[:upper:]' | cut -c1-8)" \ --expressload --relocs "$RELOC" --stack-size "${GNO_STACK_SIZE:-0x4000}" ls -la "$OUT" echo "done: $OUT (run with: bash scripts/runInGno.sh $OUT --check 0x025000=C0DE)"