Files
Syphon_Filter_3/Makefile
T
Christopher Williams 2000cc4101 phase7: census duplicate bodies and expose a zero band of false positives
Matching conventions require a duplicate check before registering, because a
shared body is matched once and registered once per address. Phase 6 did that
check by hand and found one 12-byte pair. tools/sf3_dupes now hashes every
derived extent body and groups exact duplicates.

Results: 2284 extents, 65 multi-address groups, 2104 singletons. Only 10 groups
contain code (24 addresses, all exact-graded); 55 are all-zero bodies. The
hand-found pair 0x800262E0/0x800262EC is reproduced as g0002, which is the check
that the census measures what it claims. The largest real groups are 712 bytes
(0x8001084C/0x800189E8) and 436 bytes.

The zero groups are a real finding: 252 extents have all-zero bodies, 245 inside
the zero band 0x80147000..0x80170000. The cause is the inventory's jal grade,
which decodes every word as an instruction -- in a data region a word with
opcode 3 is graded as a call whose target lands in the zero band. The census
flags those groups rather than hiding them, and the worklist must exclude
degenerate bodies.

The census is tracked rather than ignored as the plan said, because it holds
addresses, sizes and grades only (the same class as the tracked inventory and
extents tables) and the worklist must be reproducible from tracked inputs. The
content hash is computed and never written.
2026-09-23 22:15:51 -04:00

126 lines
4.2 KiB
Makefile

# Phase 3 all-assembly baseline orchestration.
# All original and generated ROM-derived inputs/outputs remain ignored.
SHELL := /usr/bin/bash
EXE := extracted/SCUS_946.40;1
MANIFEST := extracted/MANIFEST.tsv
SPLAT := tools/splat/.venv/bin/splat
AS := tools/mipsel-none-elf-binutils/prefix/usr/bin/mipsel-none-elf-as
LD := tools/mipsel-none-elf-binutils/prefix/usr/bin/mipsel-none-elf-ld
OBJCOPY := tools/mipsel-none-elf-binutils/prefix/usr/bin/mipsel-none-elf-objcopy
ASM_ROOT := asm
SPLAT_CONFIG := $(ASM_ROOT)/scus_946_40.yaml
SPLAT_OUTPUT := $(ASM_ROOT)/generated
LINKER_SCRIPT := $(ASM_ROOT)/scus_946_40.ld
BUILD := build
ELF := $(BUILD)/scus_946_40.elf
REBUILT := $(BUILD)/scus_946_40.rebuilt
INPUT_REPORT := .run/p3-exe-info.tsv
# Phase 5 ordered code build: C regions listed in the tracked registry are
# compiled with the identified toolchain and linked in address order between
# data fallbacks taken from the original executable. An empty registry
# reproduces the all-payload data baseline exactly.
REGIONS := config/regions.tsv
SYMBOLS := config/symbols.tsv
INVENTORY := config/function_inventory.tsv
EXTENTS := config/function_extents.tsv
DUPES := config/duplicate_bodies.tsv
MATCH := tools/sf3_match
EXTENTS_TOOL := tools/sf3_extents
DUPES_TOOL := tools/sf3_dupes
CODE_OUT := build/code
EXPECTED_SHA1 := e173426c157384ebf1b6caf8c6fea18a85a14af9
.PHONY: all validate split assemble link binary code gate extents extents-verify dupes test check clean
all: binary
validate:
@test -f "$(EXE)"
@test -f "$(MANIFEST)"
@mkdir -p .run
@./tools/sf3_extract psx-exe-info "$(EXE)" "$(MANIFEST)" > "$(INPUT_REPORT)"
split: validate
@test -f "$(SPLAT)"
@test -f "$(SPLAT_CONFIG)"
@cd "$(ASM_ROOT)" && ../"$(SPLAT)" split "$$(basename "$(SPLAT_CONFIG)")" --disassemble-all
assemble: split
@test -d "$(SPLAT_OUTPUT)" && test ! -L "$(SPLAT_OUTPUT)"
@test -f "$(AS)"
@test ! -L "$(BUILD)"
@mkdir -p "$(BUILD)"
@while IFS= read -r source; do \
rel="$${source#$(ASM_ROOT)/}"; \
object="$(BUILD)/$${rel}.o"; \
mkdir -p "$$(dirname "$$object")"; \
"$(AS)" -march=r3000 -G0 -I "$(ASM_ROOT)/include" -o "$$object" "$$source"; \
done < <(find "$(SPLAT_OUTPUT)" -type f -name '*.s' -print | sort)
link: assemble
@test -f "$(LINKER_SCRIPT)"
@test -f "$(LD)"
@rm -f "$(ELF)"
@"$(LD)" -T "$(LINKER_SCRIPT)" -o "$(ELF)"
binary: link
@test -f "$(OBJCOPY)"
@rm -f "$(REBUILT)"
@"$(OBJCOPY)" -O binary "$(ELF)" "$(REBUILT)"
# Ordered code build and full-binary gate (Phase 5). `code` builds only;
# `gate` builds and then requires the whole executable to be byte-identical.
code: validate
@test -f "$(MATCH)"
@test -f "$(REGIONS)"
@test -f "$(SYMBOLS)"
@rm -rf "$(CODE_OUT)"
@"$(MATCH)" build --exe "$(EXE)" --regions "$(REGIONS)" --symbols "$(SYMBOLS)" --out "$(CODE_OUT)"
gate: validate
@test -f "$(MATCH)"
@test -f "$(REGIONS)"
@test -f "$(SYMBOLS)"
@rm -rf "$(CODE_OUT)"
@"$(MATCH)" gate --exe "$(EXE)" --regions "$(REGIONS)" --symbols "$(SYMBOLS)" --out "$(CODE_OUT)" \
--expect-sha1 "$(EXPECTED_SHA1)"
# Function extents (Phase 7). `extents` regenerates the tracked table from the
# inventory; `extents-verify` re-derives it and requires every registered region
# to agree, so a region can never silently disagree with the derived extent.
extents: validate
@test -f "$(EXTENTS_TOOL)"
@test -f "$(INVENTORY)"
@"$(EXTENTS_TOOL)" scan --exe "$(EXE)" --inventory "$(INVENTORY)" --out "$(EXTENTS)" --force
extents-verify: validate
@test -f "$(EXTENTS_TOOL)"
@test -f "$(INVENTORY)"
@test -f "$(EXTENTS)"
@"$(EXTENTS_TOOL)" verify --exe "$(EXE)" --inventory "$(INVENTORY)" \
--extents "$(EXTENTS)" --regions "$(REGIONS)"
# Duplicate-body census (Phase 7): groups byte-identical bodies so a shared body
# is matched once and registered once per address.
dupes: validate
@test -f "$(DUPES_TOOL)"
@test -f "$(EXTENTS)"
@"$(DUPES_TOOL)" census --exe "$(EXE)" --extents "$(EXTENTS)" --out "$(DUPES)" --force
# Verification gates. `test` is synthetic-only and needs no game input;
# `check` adds the extents check and the full-binary byte gate (which do).
test:
@PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tools/tests
check: test extents-verify gate
clean:
@if test -e "$(BUILD)"; then \
test -d "$(BUILD)" && test ! -L "$(BUILD)"; \
rm -rf "$(BUILD)"; \
fi