Overview

Implementation: crates/asset/src/overlay_ptr_table.rs.

Layout

+0x00   u32  ptr_0      ; address in 0x801C0000..=0x801FFFFF (overlay window)
+0x04   u32  ptr_1      ; same range
...
+N*4    u32  ptr_{N-1}  ; last pointer (still in range)
+(N+1)*4 ...            ; first non-pointer u32 (typically MIPS code, sometimes
                        ; a `jr ra; nop` stub or a leading ASCII string)

The overlay window 0x801C0000..0x801FFFFF is the RAM region reserved for swappable code - a valid pointer into it is a strong sign the blob expects to live there. The pointer-table length N ranges from 4 to 64. Tables come in three shapes:

  • Function entry-point tables - small, monotonic; one slot per public function.
  • Switch dispatch tables - larger, repeating; emitted by the C compiler for switch(x) over a dense integer range.
  • Per-mode actor vtables - small alphabet of 3 distinct values across N slots.

Detection

Two checks produce zero overlap with already-named formats:

  1. The first u32 is in 0x801C0000..=0x801FFFFF (the overlay window).
  2. The run of consecutive overlay-pointer u32s is between 4 and 64 long.

Monotonicity is not required - switch dispatch tables legitimately contain repeating handler addresses.

Cluster anatomy

All matches cluster in the 0900..=0968_xxx_dat PROT range - sized 14 KB to 160 KB. Pointer-range distribution:

  • 30 entries: 0x801F6Axx0x801F71xx cluster (small function-entry tables, monotonic, 5–14 entries).
  • 12 entries: 0x801F84xx+ cluster (some monotonic, some switch dispatch with repeating handlers).

A handful of entries lead with an ASCII title string before the pointer table - the title is the battle special-attack name the overlay stages, not a song. Per entry (extraction numbering):

  • 0907_xxx_dat.BIN "Hell's Music" - Nighto's summon stager, capture-pinned on the spell-0x85 slot of the summon loader's 903..=913 range; the SCUS spell table carries the same name, and summon.dat's attack-name records list it parallel to Gimard's "Burning Attack".
  • 0924_xxx_dat.BIN "Ultimate Rave" and 0927_xxx_dat.BIN "Dark Eclipse" - the same attack-titled, stager-shaped family (part-spawn call census matches the pinned stagers); their loader callsites are computed rather than constant, but which action ids drive them is no longer open - both are capture-pinned mid-cast off the loader-B current id: 0924 is the rare-Seru flute summon Lippian (spell 0x96) and 0927 is Juggernaut on Evil Seru Magic (spell 0x99).
  • 0957_xxx_dat.BIN - a different shape: its head is a summon string table (Dies / Puera / Both / Damage / Recover) followed by an absolute-pointer table and code - the slot-B summon_effect_table overlay.

All the attack-titled entries sit in the static overlay map at slot-B base 0x801F69D8. The titles look like song names ("Hell's Music" reads like a Disco King dance track) but they are not: the dance overlay (0980) contains zero slot-B loader callsites - its music is sequenced BGM. See static overlay pipeline.

Reading the format

use legaia_asset::overlay_ptr_table;

if let Some(t) = overlay_ptr_table::detect(buf) {
    println!("Overlay pointer table: {} entries, first=0x{:08x}, last=0x{:08x}",
             t.count, t.first_ptr, t.last_ptr);
}

Each entry can be imported into Ghidra (the disassembler this project uses) via scripts/ghidra-analysis/bulk-import-overlays.sh once the load address is determined; the pointer values bound the load address from above (<= min_ptr).

See also