At a glance

In the game
Mostly battle code: the 0903..=0966 band is the 64 slot-B cast / summon modules, one per special attack, paged in when that attack is cast; 0968 / 0969 are the two boss-stage modules.
Magic / marker
No header - the blob begins with a MIPS function prologue (addiu sp, sp, -X = 0x27BDFFxx)
Lives in
PROT.DAT entries in the 0901..=0969 range (extraction index), 14-37 KB each; loads into the overlay window 0x801C0000..0x80200000
Parser
legaia_overlay_images::mips_overlay::detect (crates/overlay-images/src/mips_overlay.rs); category mips_overlay in the categorize pipeline
Confidence
Inferred - a shape heuristic with zero false positives over the corpus, not a loader trace; each blob's load base comes from the asset chain that pulls it in.
Used by
Static overlay pipeline, Overlay capture

Layout

Nothing on the disc labels these entries as code - they look like any other binary blob. Every compiled MIPS function opens by moving the stack pointer down to make room for its locals, so a blob that begins with that instruction is a code image whose entry function starts at byte 0.

The detector reads only the first two words; everything after them is the overlay body.

OffsetSizeFieldMeaning
+0x004first instruction0x27BDFFxx - addiu sp, sp, -X, the negative stack adjust that opens a compiled function
+0x044prologue follow-upsw ra/s* (0xAFB?_00XX), or another addiu / lui / lw / R-type - the second instruction of the entry function's prologue
+0x08restcodeThe overlay body, position-dependent on its load base

Detection

Three checks together produce zero false positives across the corpus:

  1. u32_le[0] & 0xFFFF_FF00 == 0x27BD_FF00 - addiu sp, sp, -X.
  2. (u32_le[0] & 0xFF) ∈ [0x80, 0xF8] - only accept reasonable stack adjustments (8 to 128 bytes).
  3. u32_le[1]'s 6-bit MIPS opcode field is one of the common function-prologue follow-ups (sw, addiu, lui, lw, R-type, ldc/sdc).
use legaia_overlay_images::mips_overlay;

if let Some(m) = mips_overlay::detect(buf) {
    println!("MIPS overlay: stack frame = {} bytes; second op = {:#04x}",
             m.stack_frame_bytes, m.second_op);
}

Where they sit and what they do

  • Range. Every match is in the 0901..=0969 extraction range, 14 KB to 37 KB, with one 163 KB outlier at 0969_xxx_dat.BIN.
  • Load base. The overlay window is 0x801C0000..0x80200000; each blob loads at a fixed offset inside it, determined by the asset chain that pulls it in. Recovered bases are committed in crates/asset/data/static-overlays.toml.
  • What the band holds. The 0903..=0966 entries are the 64 slot-B cast / summon images, each one special attack's stager (slot-B module layout, cast modules); 0968 / 0969 are the two boss-stage modules (battle). Entries that lead with a pointer table instead of a prologue are covered by the sister detector.
  • Importing. Once a base is known, scripts/ghidra-analysis/bulk-import-overlays.sh loads the blob into Ghidra (the disassembler this project uses) at that base.

Trusting an address from an overlay dump

A dumped function's printed address is only as good as the base the dump was made at; a filename prefix is not evidence of the base. Before citing an overlay address, run the byte-match arbiter (scripts/ghidra-analysis/classify-worklist.py --explain <addr>) and trust its image= verdict. Only a REAL self-entry body at a recovered base attests a distinct function at its printed address.

Failure modeWhere it bitesWhat the arbiter reports
Mis-recovered baseThe bat_back_dat (PROT 0896) dump family, neither import of which is at the image's own base 0x801D4DF0Field / battle bodies or interior fragments - never a standalone 0896 function at the printed VA
Relocation duplicateDebug-menu (0971), minigame (0977 / 0978) and menu (0899) overlays re-image a shared library at a different base per modeDUPLICATE of the canonical VA in 0970 / 0972 / 0899
Inherited CDNAME labelThe other_game block opens at extraction 0972 and its name carries forward to 0977Name by extraction index: 0977 is the Muscle Dome door/init slot, not a fishing overlay; 0978 opens monster_test
Inherited CDNAME label, againThe monster_test block opens at extraction 0978 and its names carry forward tooExtraction 0981 wears the label while its code is the overworld map display (game mode 0x0D) at 0x801CE818 - entry 0x801CE850 (the display tick), operands DAT_80073EE0 / uRam8007b970 / _DAT_80089118
Details: the two 0896 imports and the re-image pairs
  • PROT 0896 is dumped twice, neither at a runtime base: an untagged batch at 0x801C0000, whose prints above 0896's own 0x9000 bytes read through into the field (0897) and battle-action (0898) overlays, and a batch tagged [overlay_0896 base=0x801C5818] - a phantom base recovered from a jal. No dump in this family can be cited by its printed address. Per-program re-key law: docs/reference/overlay-va-aliases.md.
  • The re-image pattern is the same one functions records for 0900↔0901 and 0965↔0967: bodies byte-identical modulo relocation to an already-dumped body.
  • A CDNAME label is a hint, not a verdict - see CDNAME numbering.

How we know

Provenance: the detector, the overlay window, per-blob bases, attestation
ClaimEvidenceWhere
Prologue shape identifies codeZero false positives over every PROT entry; every match disassembles as MIPS from byte 0crates/overlay-images/src/mips_overlay.rs, categorize sweep
Overlay window 0x801C0000..0x80200000Load targets of the overlay loader; RAM mapMemory map, Boot sequence
Per-blob load basesStatically recovered from the loader constants and cross-checked against capturescrates/asset/data/static-overlays.toml, static overlay pipeline
Address attestation rulesByte-match of each dumped body against every imagescripts/ghidra-analysis/classify-worklist.py, docs/tooling/dump-corpus-integrity.md

See also