phase6: correct the compiler to PsyQ 4.0 (gcc-2.7.2-psx) and register the framed batch
This commit is contained in:
@@ -41,27 +41,27 @@ baseline, not a recovery of the original program structure.
|
||||
|
||||
## Toolchain (pinned by byte evidence)
|
||||
|
||||
The original compiler was identified in Phase 5 by fingerprinting candidate compilers against the
|
||||
executable and confirming the result with the SDK's own binary:
|
||||
The original compiler was re-identified in Phase 6 by comparing candidate compilers against the
|
||||
SDK's own binaries and the executable:
|
||||
|
||||
| Role | Component | Evidence |
|
||||
|---|---|---|
|
||||
| Compiler | **`egcs-2.91.66 19990314` (egcs-1.1.2), target `mips-sony-psx`** — the `CC1PSX.EXE` of PsyQ SDK 4.5 | SDK README banner; the real binary executed and compared; the open `gcc-2.91.66-psx` build is instruction-identical to it across ~990 probe instructions |
|
||||
| Assembler | **`ASPSX` 2.81** (Sony) | SDK banner; `maspsx` is the open emulator candidate |
|
||||
| Compiler | **`GNU C 2.7.2.SN32.3.7.0002`** — the `CC1PSX.EXE` of PsyQ SDK 4.0 | the real binary executed and compared; the open `gcc-2.7.2-psx` build is instruction-identical to it across all 21 probe files |
|
||||
| Assembler | **`ASPSX` 2.56** (Sony) | SDK 4.0 banner; `maspsx` is the open emulator |
|
||||
| Linker / binary tools | GNU `mipsel-none-elf` binutils | Phase 3 local build, recorded in `docs/SETUP.md` |
|
||||
| Splitter | `splat` (+ `spimdisasm`, `rabbitizer`) | Phase 3 |
|
||||
|
||||
Working compiler invocation (input must be **preprocessed**; `cc1` rejects comments and directives):
|
||||
|
||||
```
|
||||
gcc-2.91.66-psx/cc1 -quiet -O2 -G0 -mno-split-addresses # then assemble with GNU as
|
||||
gcc-2.7.2-psx/cc1 -quiet -O2 -G0 # then maspsx, then GNU as
|
||||
```
|
||||
|
||||
`-mno-split-addresses` is required: the game's code uses the ASPSX-style symbolic-address form that
|
||||
the assembler expands through `$at`, rather than the compiler's own default split form. The compiler
|
||||
itself is **open**: `decompals/old-gcc` release 0.17 publishes `gcc-2.91.66-psx`, and no proprietary
|
||||
SDK is needed for the matching build. The full derivation, including a corrected earlier conclusion,
|
||||
is in [`docs/PHASE5_TOOLCHAIN_FINGERPRINT.md`](docs/PHASE5_TOOLCHAIN_FINGERPRINT.md).
|
||||
The macro address form is this compiler's default. Phase 5 had selected `egcs-2.91.66` (PsyQ 4.5),
|
||||
which matches simple functions but emits a different framed epilogue; the executable's framed code
|
||||
identifies PsyQ 4.0. The compiler is **open**: `decompals/old-gcc` release 0.17 publishes
|
||||
`gcc-2.7.2-psx`, and no proprietary SDK is needed for the matching build. The full derivation is in
|
||||
[`docs/PHASE6_TOOLCHAIN_CORRECTION.md`](docs/PHASE6_TOOLCHAIN_CORRECTION.md).
|
||||
|
||||
## Build it from your own disc
|
||||
|
||||
@@ -151,7 +151,7 @@ own licenses:
|
||||
[`ghidra_psx_ldr`](https://github.com/lab313ru/ghidra_psx_ldr) (lab313ru) — the static oracle and its PSX loader
|
||||
- [PCSX-Redux](https://github.com/grumpycoders/pcsx-redux) — the runtime oracle
|
||||
- GNU binutils — the MIPS assembler, linker and `objcopy`
|
||||
- The Sony PsyQ SDK — proprietary; **never distributed**, only referenced by checksum. The PsyQ 4.4/4.5/4.6
|
||||
- The Sony PsyQ SDK — proprietary; **never distributed**, only referenced by checksum. The PsyQ 4.0/4.1/4.4/4.5/4.6
|
||||
compiler binaries were obtained from [`mkst/esa`](https://github.com/mkst/esa)'s `psyq-binaries` release
|
||||
and are used only as a verification reference
|
||||
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
0x80012780 0x8001278C src/func_80012780.c
|
||||
0x80017AD4 0x80017AE8 src/func_80017AD4.c
|
||||
0x80017AE8 0x80017AF8 src/func_80017AE8.c
|
||||
0x80017DD0 0x80017DF0 src/func_80017DD0.c
|
||||
0x80024C14 0x80024C34 src/func_80024C14.c
|
||||
0x80026264 0x80026274 src/func_80026264.c
|
||||
0x800262E0 0x800262EC src/func_800262E0.c
|
||||
0x800262EC 0x800262F8 src/func_800262E0.c
|
||||
0x8002D2A0 0x8002D2BC src/func_8002D2A0.c
|
||||
0x8002D2BC 0x8002D2D4 src/func_8002D2BC.c
|
||||
0x80036308 0x80036328 src/func_80036308.c
|
||||
0x800697A4 0x800697C4 src/func_800697A4.c
|
||||
|
||||
|
@@ -18,3 +18,7 @@ _gp 0x80121938
|
||||
D_80121974 0x80121974 gp
|
||||
D_80121B18 0x80121B18 gp
|
||||
D_80121B14 0x80121B14 gp
|
||||
func_80024668 0x80024668
|
||||
func_800F4098 0x800F4098
|
||||
func_800695D8 0x800695D8
|
||||
func_8002F404 0x8002F404
|
||||
|
||||
|
@@ -101,7 +101,7 @@ symbol **address** (`la`) reproduce the original's `addiu` form (cookbook findin
|
||||
## Toolchain stages
|
||||
|
||||
A C region is built `cpp` → `cc1` → **`maspsx`** → GNU `as` → `ld` → `objcopy`. The maspsx stage
|
||||
emulates ASPSX 2.81 (the version on the PsyQ 4.5 SDK banner): it emits `.set noreorder` and explicit
|
||||
emulates ASPSX 2.56 (the version on the PsyQ 4.0 SDK banner): it emits `.set noreorder` and explicit
|
||||
`nop`s so delay-slot scheduling matches the original. `--no-maspsx` disables it for comparison;
|
||||
`--aspsx-version` overrides the pinned version.
|
||||
|
||||
|
||||
+36
-35
@@ -8,29 +8,34 @@ project; each claim was observed here first.
|
||||
|
||||
| Role | Identity | Basis |
|
||||
|---|---|---|
|
||||
| Compiler | `egcs-2.91.66 19990314` (egcs-1.1.2), target `mips-sony-psx` — PsyQ 4.5 `CC1PSX` | SDK README banner; the real binary executed and compared |
|
||||
| Open substitute | `decompals/old-gcc` 0.17 `gcc-2.91.66-psx` | Instruction-identical to the real `CC1PSX` across ~990 probe instructions |
|
||||
| Assembler | `ASPSX` 2.81 (Sony) | SDK banner |
|
||||
| Working invocation | `cc1 -quiet -O2 -G0 -mno-split-addresses`, then GNU `as -march=r3000 -G0` | Byte-identical ranges; `make gate` |
|
||||
| Compiler | `GNU C 2.7.2.SN32.3.7.0002` — PsyQ 4.0 `CC1PSX` | the real binary executed and compared; its banner |
|
||||
| Open substitute | `decompals/old-gcc` 0.17 `gcc-2.7.2-psx` | instruction-identical to the real `CC1PSX` 4.0 across 21 probe files |
|
||||
| Assembler | `ASPSX` 2.56 (Sony) | SDK 4.0 banner (`Psy-Q ASPSX version 2.56`) |
|
||||
| Working invocation | `cc1 -quiet -O2 -G0`, then maspsx `--aspsx-version=2.56`, then GNU `as -march=r3000 -G0` | Byte-identical ranges; `make gate` |
|
||||
|
||||
> **Under review (Phase 6).** This identification does not explain the whole executable. Framed
|
||||
> functions use a reorder-mode epilogue that `egcs-2.91.66` + maspsx does not produce, and two
|
||||
> verified functions require opposite assembler scheduling. See finding 11 and
|
||||
> [PHASE6_FRAMED_BLOCKER.md](PHASE6_FRAMED_BLOCKER.md).
|
||||
> **Corrected in Phase 6.** Phase 5 selected `egcs-2.91.66` (PsyQ 4.5). That compiler matches simple
|
||||
> functions but emits a different framed epilogue, and it does not match the executable. The real
|
||||
> PsyQ 4.0 `CC1PSX` is 2.7.2-based, and `gcc-2.7.2-psx` is instruction-identical to it across all 21
|
||||
> probe files. See [PHASE6_TOOLCHAIN_CORRECTION.md](PHASE6_TOOLCHAIN_CORRECTION.md).
|
||||
|
||||
## Findings
|
||||
|
||||
### 1. `-mno-split-addresses` is mandatory
|
||||
### 1. The macro address form is this compiler's default
|
||||
|
||||
`cc1` has two address-materialisation modes, and only one of them matches.
|
||||
`cc1` has two address-materialisation modes:
|
||||
|
||||
- **`-msplit-addresses`** (the real `CC1PSX` default) emits explicit sequences such as
|
||||
`lui $3,%hi(sym)` / `lw $2,%lo(sym)($3)`. **Does not match.**
|
||||
- **`-mno-split-addresses`** emits assembler **macros** (`lw $2,sym`, `sw $4,sym`, `la $2,sym`) that
|
||||
the assembler expands. **Matches.**
|
||||
- explicit `lui $3,%hi(sym)` / `lw $2,%lo(sym)($3)` sequences (PsyQ 4.1 and later default), and
|
||||
- assembler **macros** (`lw $2,sym`, `sw $4,sym`, `la $2,sym`) that the assembler expands.
|
||||
|
||||
*Basis:* oracle ranges `0x80085B80`, `0x800F3160` — byte-identical only under `-mno-split-addresses`.
|
||||
*Limit:* proven for symbol loads, symbol stores and `la`; not yet exhaustively for every construct.
|
||||
The executable uses the **macro** form. PsyQ 4.0's `CC1PSX` (`gcc-2.7.2-psx`) emits it by default;
|
||||
later compilers (2.8+, egcs) emit the explicit form and must be forced into macros with
|
||||
`-mno-split-addresses`. Phase 5 recorded that flag as mandatory only because it was using the wrong
|
||||
compiler.
|
||||
|
||||
*Basis:* the real PsyQ 4.0 `CC1PSX` and `gcc-2.7.2-psx` emit `sw $4,g_store` / `la $2,sym` by
|
||||
default and match the executable; the real PsyQ 4.1 `CC1PSX` emits the explicit `$2`-scratch form,
|
||||
which does not match `0x800F3160`.
|
||||
*Limit:* proven for symbol loads, symbol stores and `la`.
|
||||
|
||||
### 2. Symbol load — the macro expands into the destination register
|
||||
|
||||
@@ -50,17 +55,17 @@ project; each claim was observed here first.
|
||||
|
||||
### 4. `la` differs between assemblers — resolved by maspsx + link-time symbols
|
||||
|
||||
GNU `as` and ASPSX 2.81 expand the `la` macro differently:
|
||||
GNU `as` and ASPSX 2.56 expand the `la` macro differently:
|
||||
|
||||
- **GNU `as` in reorder mode** expands `la rt,sym` with **`ori`** and an unadjusted `%hi`
|
||||
(`lui rt,0x8010` / `ori rt,rt,0xf354`), and it also **reorders** the following store into a jump's
|
||||
delay slot.
|
||||
- **ASPSX 2.81** uses **`addiu`** with a sign-adjusted `%hi` (`lui rt,0x8011` / `addiu rt,rt,-3244`)
|
||||
- **ASPSX 2.56** uses **`addiu`** with a sign-adjusted `%hi` (`lui rt,0x8011` / `addiu rt,rt,-3244`)
|
||||
and does not reorder.
|
||||
|
||||
The fix has two parts, both now in the harness:
|
||||
|
||||
1. Run `maspsx --aspsx-version=2.81` between `cc1` and GNU `as`. maspsx emits `.set noreorder` and
|
||||
1. Run `maspsx --aspsx-version=2.56` between `cc1` and GNU `as`. maspsx emits `.set noreorder` and
|
||||
explicit `nop`s, so the delay-slot scheduling matches ASPSX.
|
||||
2. Leave symbols **undefined** at assembly time and resolve them with the **linker** (`ld --defsym`).
|
||||
GNU `as` then emits `lui %hi` + `addiu %lo` relocations, and the linker applies the HI16 carry
|
||||
@@ -133,27 +138,23 @@ over 1,286 distinct addresses. See [PHASE6_SMALL_DATA.md](PHASE6_SMALL_DATA.md).
|
||||
*Limit:* the numeric `-G` threshold is **not recoverable** from the code (object sizes are unknown);
|
||||
`-mgpopt`/`-mno-gpopt` produce identical `cc1` output for these functions.
|
||||
|
||||
### 11. Framed epilogues use reorder-mode scheduling — unresolved
|
||||
### 11. Framed epilogues use reorder-mode scheduling
|
||||
|
||||
- **322** framed functions end `lw ra,off(sp)` / `addiu sp,sp,N` / `jr ra` / `nop` (shape A).
|
||||
- `egcs-2.91.66` + `-mno-split-addresses` + maspsx produces `lw ra,off(sp)` / `nop` / `jr ra` /
|
||||
`addiu sp,sp,N` (shape B). The **real** PsyQ 4.5 `CC1PSX` and the **real** `ASPSX` 2.81 also
|
||||
produce shape B.
|
||||
- The `gcc-2.6.0-psx` / `2.6.3-psx` / `2.7.2-psx` / `2.7.2-cdk` builds emit the epilogue in reorder
|
||||
mode and reproduce shape A byte-for-byte (test case `0x80024C14`).
|
||||
- Separately, `q_sym_store` (`0x800F3160`) and `func_8002D2BC` (`0x8002D2BC`) require **opposite**
|
||||
assembler scheduling, so no single assembler/maspsx configuration reproduces both.
|
||||
Framed functions end `lw ra,off(sp)` / `addiu sp,sp,N` / `jr ra` / `nop` (322 of them; only 13 sites
|
||||
in the CRT region use the other order). PsyQ 4.0's `CC1PSX` emits this epilogue in **reorder** mode
|
||||
and the assembler schedules it; `egcs-2.91.66` emits `.set noreorder` with the stack restore in the
|
||||
jump delay slot and does not match. This was the discriminator that corrected the compiler
|
||||
identification.
|
||||
|
||||
*Basis:* the epilogue census (322 vs 13), the `0x80024C14` compiler matrix, and real-`ASPSX`
|
||||
assembly of the cc1 output.
|
||||
*Limit:* **open** — the compiler identity and the assembler model need revision before framed
|
||||
functions can be matched. See [PHASE6_FRAMED_BLOCKER.md](PHASE6_FRAMED_BLOCKER.md).
|
||||
*Basis:* the epilogue census (322 vs 13) and the `0x80024C14` compiler matrix; four framed functions
|
||||
are now registered and byte-identical.
|
||||
*Limit:* one bounded anomaly remains — `0x800F3160`, a 12-byte symbol store whose store-in-delay-slot
|
||||
scheduling no tested assembler reproduces. See [PHASE6_FRAMED_BLOCKER.md](PHASE6_FRAMED_BLOCKER.md).
|
||||
|
||||
## Open questions
|
||||
|
||||
- **Framed-function epilogue and assembler scheduling are unresolved** (finding 11): the original
|
||||
compiler is a 2.6/2.7-family build, or egcs-2.91.66 with an unidentified flag; and
|
||||
`q_sym_store`/`func_8002D2BC` conflict under every tested assembler configuration.
|
||||
- One bounded scheduling anomaly: `0x800F3160` (`lui at` / `jr ra` / `sw a0,off(at)`) is 12 bytes,
|
||||
but PsyQ 4.0 `CC1PSX` + ASPSX 2.56 gives 16 (`sw` before the jump). It is not registered.
|
||||
- The exact `-G` small-data threshold is not recoverable from the code; the per-symbol `gp` form is
|
||||
reconstructed from the original's accesses instead (finding 10).
|
||||
- Whether `-mgpopt` was passed is not observable: it does not change `cc1` output for the cases
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
# Phase 6 — Framed-Function and Assembler-Scheduling Blocker
|
||||
|
||||
**Scope:** P6-T6 (the matching batch). **Status: OPEN — recorded, not resolved.** This blocks the
|
||||
> **RESOLVED (2026-09-23).** The compiler was re-identified as **PsyQ 4.0** (`gcc-2.7.2-psx`), which
|
||||
> reproduces the framed epilogue; the framed shape is now matched. See
|
||||
> [PHASE6_TOOLCHAIN_CORRECTION.md](PHASE6_TOOLCHAIN_CORRECTION.md). The record below is kept as the
|
||||
> evidence that drove the correction; one bounded anomaly (`0x800F3160`) remains open.
|
||||
|
||||
**Scope:** P6-T6 (the matching batch). **Original status: OPEN — recorded, not resolved.** This blocks the
|
||||
"call with a frame" shape and any framed function, and it puts the Phase 5 compiler identification
|
||||
back in question. It does **not** affect the 8 already-registered matches.
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Phase 6 — Toolchain Correction: PsyQ 4.0, not PsyQ 4.5
|
||||
|
||||
**Scope:** P6-T6 (option A — re-identify the compiler). **Status: complete.** This supersedes the
|
||||
Phase 5 compiler identification in `docs/PHASE5_TOOLCHAIN_FINGERPRINT.md`.
|
||||
|
||||
## Result
|
||||
|
||||
| Role | Identity | Basis |
|
||||
|---|---|---|
|
||||
| Compiler | **PsyQ 4.0 `CC1PSX`**, banner `GNU C 2.7.2.SN32.3.7.0002` | the real binary executed and compared |
|
||||
| Open substitute | **`gcc-2.7.2-psx`** | instruction-identical to the real `CC1PSX` 4.0 across **all 21** probe files |
|
||||
| Assembler | **ASPSX 2.56** (SDK 4.0 banner) | `Psy-Q ASPSX version 2.56` |
|
||||
| maspsx pin | `--aspsx-version=2.56` | matches the SDK 4.0 assembler version |
|
||||
| Flags | `-quiet -O2 -G0` | the macro address form is this compiler's default |
|
||||
|
||||
The loader's `PsyQ Version = 4.5.0` describes the **runtime library** version, not the compiler that
|
||||
built the code.
|
||||
|
||||
## How Phase 5 reached the wrong answer
|
||||
|
||||
- Phase 5 compared the **real PsyQ 4.5 `CC1PSX`** against the open `gcc-2.91.66-psx` and found them
|
||||
instruction-identical. That is true — for SDK 4.5. It does not show that 4.5 built the game.
|
||||
- Phase 5's byte-identical oracles (struct load/store, symbol load/store) are reproduced by **all ten**
|
||||
candidates; the record explicitly says so. They cannot discriminate.
|
||||
- Phase 5's `-mno-split-addresses` conclusion was an artifact of using a compiler (2.8+) whose default
|
||||
is the explicit split form. The correct compiler emits the macro form by default and has no such flag.
|
||||
|
||||
## Evidence
|
||||
|
||||
1. **Framed epilogue census.** 322 game functions end `lw ra,off(sp)` / `addiu sp,sp,N` / `jr ra` /
|
||||
`nop`; only 13 sites (CRT region) use the other order. `egcs-2.91.66` emits `.set noreorder` with
|
||||
the stack restore in the jump delay slot, i.e. the minority order.
|
||||
|
||||
2. **Compiler matrix on the framed wrapper `0x80024C14`:**
|
||||
|
||||
| Compiler | Result |
|
||||
|---|---|
|
||||
| `gcc-2.6.0-psx`, `gcc-2.6.3-psx`, `gcc-2.7.2-psx`, `gcc-2.7.2-cdk` | **MATCH** |
|
||||
| `gcc-2.8.0-psx`, `gcc-2.8.1-psx`, `gcc-2.91.66-psx`, `gcc-2.95.2-psx` | DIFF |
|
||||
| real PsyQ 4.0 `CC1PSX` | emits the same shape as the 2.7.2 family |
|
||||
|
||||
3. **Real SDK comparison.** With normalization, the real `CC1PSX` 4.0 output was compared to every
|
||||
open candidate across 21 probe files:
|
||||
|
||||
| Candidate | Probe files identical to real `CC1PSX` 4.0 |
|
||||
|---|---|
|
||||
| **`gcc-2.7.2-psx`** | **21 / 21** |
|
||||
| `gcc-2.6.0-psx`, `gcc-2.6.3-psx` | 6 / 21 |
|
||||
| `gcc-2.7.2-cdk`, `gcc-2.8.0-psx`, `gcc-2.8.1-psx` | 1 / 21 |
|
||||
| `gcc-2.91.66-psx`, `gcc-2.95.2-psx` | 0 / 21 |
|
||||
|
||||
4. **Symbol form.** Real `CC1PSX` 4.0 emits the macro form by default (`sw $4,g_store`, `la $2,sym`);
|
||||
real `CC1PSX` 4.1 emits the explicit `$2`-scratch form. The executable uses the macro form, so the
|
||||
compiler is 4.0 (or 4.5), and the framed epilogue rules out 4.5.
|
||||
|
||||
5. **Assembler versions.** SDK 4.0 ships ASPSX **2.56**, SDK 4.1 ships 2.67, SDK 4.5 ships 2.81.
|
||||
|
||||
## Corrected harness
|
||||
|
||||
`tools/sf3_match` now defaults to `tools/old-gcc/gcc-2.7.2-psx/cc1` with `-quiet -O2 -G0` and
|
||||
`--aspsx-version=2.56`. All **12 registered regions** still pass `sf3_match range` and `make gate`
|
||||
(`c_regions=12`, 0 differing bytes, SHA-1 `e173426c157384ebf1b6caf8c6fea18a85a14af9`), and the framed
|
||||
shape is now matchable.
|
||||
|
||||
## Residual anomaly (bounded, unresolved)
|
||||
|
||||
`0x800F3160` is a 12-byte symbol store whose original bytes are `lui at,0x8014` / `jr ra` /
|
||||
`sw a0,11996(at)` — the store is in the jump delay slot. PsyQ 4.0 `CC1PSX` + ASPSX 2.56 produces the
|
||||
16-byte form with the store **before** the jump. No tested (compiler, assembler) pair reproduces it:
|
||||
ASPSX 4.1 schedules the store but uses `$2` rather than `$at`; GNU `as` reorder schedules it with
|
||||
`$at` but breaks other functions. It is **not registered** and is recorded as a bounded open item in
|
||||
the cookbook.
|
||||
|
||||
## Rules
|
||||
|
||||
No rules were added.
|
||||
@@ -165,3 +165,25 @@ Both components stay ignored (`tools/psyq/` and `tools/wibo/`).
|
||||
instruction output across every probe tested (~990 instructions, twelve probe files). The open
|
||||
`gcc-2.91.66-psx` is therefore the working compiler; the proprietary binary is only a verification
|
||||
reference and is not required for the matching build.
|
||||
|
||||
## Phase 6 toolchain correction and the PsyQ 4.0/4.1 compilers (2026-09-23)
|
||||
|
||||
The framed-function work in P6-T6 showed the Phase 5 compiler identification did not explain the
|
||||
executable: framed functions use a reorder-mode epilogue that `egcs-2.91.66` (PsyQ 4.5) does not
|
||||
emit. P6-T6 therefore obtained the **PsyQ 4.0 and 4.1** compiler sets to compare compiler and
|
||||
assembler versions directly.
|
||||
|
||||
| Component | Identity | sha256 |
|
||||
|---|---|---|
|
||||
| PsyQ SDK 4.0 compilers | `CC1PSX.EXE` (banner `GNU C 2.7.2.SN32.3.7.0002`), `ASPSX.EXE` (banner `Psy-Q ASPSX version 2.56`) | `f25a4f6f044eb1b344bbbd3291aa9a4fc1a1124fc637eae9522c0a117d940e28` |
|
||||
| PsyQ SDK 4.1 compilers | `CC1PSX.EXE` (`SN32.3.7.0004`), `ASPSX.EXE` (`SDevTC ASPSX version 2.67`) | `2a2650ceb5eaa73fdc581bec4a85ccaa6ff9eeea8a4810be25a638f3cd2ebac4` |
|
||||
|
||||
- Source: `https://github.com/mkst/esa/releases/download/psyq-binaries/psyq4.0.tar.gz` and
|
||||
`psyq4.1.tar.gz`, fetched 2026-09-23. Proprietary Sony material; kept ignored under `tools/psyq/`.
|
||||
- **Result:** the executable's framed epilogues and symbol forms identify **PsyQ 4.0**. The real
|
||||
`CC1PSX` 4.0 is instruction-identical to the open `gcc-2.7.2-psx` across **all 21 probe files**;
|
||||
`gcc-2.7.2-cdk`, `gcc-2.8.x`, `gcc-2.91.66-psx` and `gcc-2.95.2-psx` match far fewer. The working
|
||||
toolchain is `gcc-2.7.2-psx` + maspsx `--aspsx-version=2.56` + GNU `as`.
|
||||
- Invocation: `tools/wibo/wibo tools/psyq/psyq4.0/psyq4.0/CC1PSX.EXE -quiet -O2 -G0 <preprocessed.c> -o <out.s>`.
|
||||
- The SDK 4.5 banner (`egcs-2.91.66`, ASPSX 2.81) remains recorded above; it is a different SDK from
|
||||
the one that built the game. See [PHASE6_TOOLCHAIN_CORRECTION.md](PHASE6_TOOLCHAIN_CORRECTION.md).
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- [x] **P6-T4 — `-G` small-data threshold from byte evidence** (complete)
|
||||
- [x] **Rules check** — re-read `AGENTS.md` mandatory behavior after P6-T4 and stated the required continuation notice.
|
||||
- [x] **P6-T5 — Evidence-graded function-boundary inventory** (complete)
|
||||
- [~] **P6-T6 — First matching batch, with duplicate sharing** — **partial**: 8 regions registered and duplicate sharing demonstrated; the "call with a frame" shape is blocked by `docs/PHASE6_FRAMED_BLOCKER.md`
|
||||
- [x] **P6-T6 — First matching batch, with duplicate sharing** (complete; the framed shape was unblocked by correcting the compiler identification)
|
||||
- [ ] P6-T7 — Cookbook, conventions, verification record, and phase gate
|
||||
|
||||
## P6-T1 — Baseline revalidation (2026-09-23)
|
||||
@@ -219,3 +219,35 @@ function). The blocker is recorded in `docs/PHASE6_FRAMED_BLOCKER.md`:
|
||||
|
||||
**Not claimed:** no framed function is matched; the Phase 5 compiler identification is recorded as
|
||||
insufficient pending developer input.
|
||||
|
||||
## P6-T6 (continued) — Toolchain correction and the framed batch (2026-09-23)
|
||||
|
||||
On developer direction ("attempt A"), the compiler was re-identified. **The original compiler is
|
||||
PsyQ 4.0, not PsyQ 4.5.**
|
||||
|
||||
- The real PsyQ 4.0 `CC1PSX` reports `GNU C 2.7.2.SN32.3.7.0002`; the open `gcc-2.7.2-psx` is
|
||||
instruction-identical to it across **all 21 probe files** (`gcc-2.6.x` match 6, `gcc-2.7.2-cdk`/2.8.x
|
||||
match 1, `egcs-2.91.66`/2.95.2 match 0).
|
||||
- SDK 4.0 ships **ASPSX 2.56** (4.1 → 2.67, 4.5 → 2.81); the harness now pins `--aspsx-version=2.56`.
|
||||
- The `-mno-split-addresses` requirement recorded in Phase 5 was an artifact of the wrong compiler;
|
||||
PsyQ 4.0 emits the macro address form by default and has no such flag.
|
||||
- Full evidence: `docs/PHASE6_TOOLCHAIN_CORRECTION.md`; SDK provenance and checksums in `docs/SETUP.md`.
|
||||
|
||||
**Delivered:** four framed functions registered — `func_80017DD0`, `func_80024C14`, `func_80036308`,
|
||||
`func_800697A4` — taking the registry to **12 regions / 11 distinct functions** across three shapes
|
||||
(leaf getter/setter, `la`/`gp`-relative, and call with a frame).
|
||||
|
||||
**Verification:**
|
||||
|
||||
| Check | Result |
|
||||
|---|---|
|
||||
| `sf3_match range` for all 12 regions with the corrected compiler | all `MATCH` |
|
||||
| `make gate` | `c_regions=12`, 0 differing bytes, SHA-1 `e173426c…`, exit 0 |
|
||||
| Synthetic suite | 86 tests pass |
|
||||
| Real-compiler agreement | `gcc-2.7.2-psx` = real PsyQ 4.0 `CC1PSX` on 21/21 probe files |
|
||||
|
||||
**Residual open item:** `0x800F3160` (12-byte symbol store with the store in the delay slot) is not
|
||||
reproduced by any tested (compiler, assembler) pair; it is not registered and is recorded in the
|
||||
cookbook.
|
||||
|
||||
**Rules check — re-read complete. Continuing with P6-T7.**
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* func_80017DD0 — 32 bytes at 0x80017DD0..0x80017DF0
|
||||
*
|
||||
* Byte-identical reconstruction of a non-leaf wrapper that calls one function
|
||||
* with a constant zero argument.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-24
|
||||
* sw ra,16(sp)
|
||||
* jal func_800F4098
|
||||
* move a0,zero (argument set in the call delay slot)
|
||||
* lw ra,16(sp)
|
||||
* addiu sp,sp,24
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the function name and the callee's name are address placeholders
|
||||
* reconstructed from the disassembly; only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern void func_800F4098(int);
|
||||
|
||||
void func_80017DD0(void) {
|
||||
func_800F4098(0);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* func_80024C14 — 32 bytes at 0x80024C14..0x80024C34
|
||||
*
|
||||
* Byte-identical reconstruction of a non-leaf wrapper: it builds a frame, calls
|
||||
* one function with no arguments, and returns.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-24
|
||||
* sw ra,16(sp)
|
||||
* jal func_80024668
|
||||
* nop
|
||||
* lw ra,16(sp)
|
||||
* addiu sp,sp,24
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* This is one of the framed functions that established the corrected
|
||||
* toolchain: PsyQ 4.0's `CC1PSX` (`GNU C 2.7.2.SN32.3.7.0002`, open equivalent
|
||||
* `gcc-2.7.2-psx`) emits this epilogue in reorder mode, which the assembler
|
||||
* schedules to `lw ra` / `addiu sp,sp,24` / `jr ra` / `nop`. `egcs-2.91.66`
|
||||
* (Phase 5's earlier selection) emits a different epilogue and does not match.
|
||||
*
|
||||
* LIMITS: the function name and the callee's name are address placeholders
|
||||
* reconstructed from the disassembly; only the compiled bytes are evidence.
|
||||
*/
|
||||
|
||||
extern void func_80024668(void);
|
||||
|
||||
void func_80024C14(void) {
|
||||
func_80024668();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* func_80036308 — 32 bytes at 0x80036308..0x80036328
|
||||
*
|
||||
* Byte-identical reconstruction of a non-leaf wrapper that forwards two
|
||||
* arguments, masking the second to an unsigned byte in the call delay slot.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-24
|
||||
* sw ra,16(sp)
|
||||
* jal func_8002F404
|
||||
* andi a1,a1,0x00ff (unsigned char argument, call delay slot)
|
||||
* lw ra,16(sp)
|
||||
* addiu sp,sp,24
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the function name, the callee's name and the parameter types are
|
||||
* hypotheses reconstructed from the disassembly; only the compiled bytes are
|
||||
* evidence. The `andi` mask is the target's default unsigned-`char` ABI.
|
||||
*/
|
||||
|
||||
extern void func_8002F404(int, unsigned char);
|
||||
|
||||
void func_80036308(int x, unsigned char y) {
|
||||
func_8002F404(x, y);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* func_800697A4 — 32 bytes at 0x800697A4..0x800697C4
|
||||
*
|
||||
* Byte-identical reconstruction of a non-leaf wrapper that forwards its first
|
||||
* argument and passes zero as the second.
|
||||
*
|
||||
* The observed instructions are:
|
||||
* addiu sp,sp,-24
|
||||
* sw ra,16(sp)
|
||||
* jal func_800695D8
|
||||
* move a1,zero (second argument set in the call delay slot)
|
||||
* lw ra,16(sp)
|
||||
* addiu sp,sp,24
|
||||
* jr ra
|
||||
* nop
|
||||
*
|
||||
* LIMITS: the function name, the callee's name and the parameter types are
|
||||
* hypotheses reconstructed from the disassembly; only the compiled bytes are
|
||||
* evidence.
|
||||
*/
|
||||
|
||||
extern void func_800695D8(int, int);
|
||||
|
||||
void func_800697A4(int x) {
|
||||
func_800695D8(x, 0);
|
||||
}
|
||||
+10
-8
@@ -32,10 +32,12 @@ in its own source or output and refuses to write into an existing directory.
|
||||
|
||||
Exit codes: 0 success/match, 1 mismatch, 2 usage or environment error.
|
||||
|
||||
Toolchain (identified in Phase 5): egcs-2.91.66 (egcs-1.1.2), target
|
||||
mips-sony-psx -- PsyQ 4.5's CC1PSX. The open decompals/old-gcc
|
||||
`gcc-2.91.66-psx` build produces instruction-identical output. Required flags:
|
||||
-O2 -G0 -mno-split-addresses. Input to cc1 must be preprocessed.
|
||||
Toolchain (identified in Phase 6, correcting Phase 5): PsyQ 4.0's `CC1PSX` reports
|
||||
`GNU C 2.7.2.SN32.3.7.0002`. The open decompals/old-gcc `gcc-2.7.2-psx` build is
|
||||
instruction-identical to it across 21 probe files. Flags: `-O2 -G0` (the macro
|
||||
address form is the default; this compiler has no `-mno-split-addresses`).
|
||||
Input to cc1 must be preprocessed. The SDK 4.0 assembler is ASPSX 2.56, which
|
||||
maspsx emulates.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -53,18 +55,18 @@ from typing import Sequence
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
DEFAULT_CC1 = REPO_ROOT / "tools/old-gcc/gcc-2.91.66-psx/cc1"
|
||||
DEFAULT_CC1 = REPO_ROOT / "tools/old-gcc/gcc-2.7.2-psx/cc1"
|
||||
_BINUTILS = REPO_ROOT / "tools/mipsel-none-elf-binutils/prefix/usr/bin"
|
||||
DEFAULT_AS = _BINUTILS / "mipsel-none-elf-as"
|
||||
DEFAULT_LD = _BINUTILS / "mipsel-none-elf-ld"
|
||||
DEFAULT_OBJCOPY = _BINUTILS / "mipsel-none-elf-objcopy"
|
||||
|
||||
DEFAULT_CPP_FLAGS = ["-E", "-P", "-undef"]
|
||||
DEFAULT_CC1_FLAGS = ["-quiet", "-O2", "-G0", "-mno-split-addresses"]
|
||||
DEFAULT_CC1_FLAGS = ["-quiet", "-O2", "-G0"]
|
||||
DEFAULT_AS_FLAGS = ["-march=r3000", "-G0"]
|
||||
DEFAULT_MASPSX = REPO_ROOT / "tools/maspsx/maspsx.py"
|
||||
# The PsyQ 4.5 SDK banner reports `SDevTC ASPSX version 2.81`.
|
||||
DEFAULT_ASPSX_VERSION = "2.81"
|
||||
# The PsyQ 4.0 SDK banner reports `Psy-Q ASPSX version 2.56`.
|
||||
DEFAULT_ASPSX_VERSION = "2.56"
|
||||
|
||||
EXE_MAGIC = b"PS-X EXE"
|
||||
HEADER_SIZE = 0x800
|
||||
|
||||
@@ -433,7 +433,7 @@ class EndToEndTests(unittest.TestCase):
|
||||
src.write_text(source, encoding="ascii")
|
||||
# Reference: the source compiled directly with the full -O0 flag set.
|
||||
ref_tools = self._toolchain(
|
||||
cc1_flags=["-quiet", "-O0", "-G0", "-mno-split-addresses"]
|
||||
cc1_flags=["-quiet", "-O0", "-G0"]
|
||||
)
|
||||
ref_obj = root / "ref.o"
|
||||
sf3_match.compile_c(src, ref_obj, root / "refwork", ref_tools)
|
||||
|
||||
Reference in New Issue
Block a user