Files
xenia-rs/RE_SYMBOLS.md
MechaCat02 6b248d71e9 docs: RE symbol map + DB re-stamp for cracked IPFB name-hash
Record the guest functions identified while cracking the IPFB TOC
name-hash: Pak_FindEntryByName (0x824609C8), Pak_HashPathName
(0x82460928), Sylph_NameHash (0x82455C78, the Barrett poly-hash),
Str_ToLowerAscii (0x825F4F90), Pak_IsIPFBHeader (0x824607B0),
Archive_StreamReadCrc32 (0x82458508, content CRC — not the name-hash),
Res3D_LoadMeshChunk (0x82640290), and g_Crc32Table (0x828992F0).

RE_SYMBOLS.md is the source of truth (names/addresses/signatures +
confidence, the name-hash algorithm, and the confirmed TOC key path
schemes unit\<ID>.tbl / weapon\<ID>.tbl). apply_re_symbols.sql re-stamps
functions.name onto sylpheed.db (wiped on regen); already applied.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:45:26 +02:00

75 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Project Sylpheed — reverse-engineered symbol map
Durable record of guest functions/data in the retail title (`default.xex`,
base `0x82000000`) that have been positively identified by RE. Addresses are
guest virtual addresses. This is the source of truth for names; the DuckDB
`sylpheed.db` (this dir) `functions.name` column can be re-stamped from here
with `apply_re_symbols.sql` (names are wiped on a full DB regen).
Confidence: **H** = behaviour proven (reproduced/verified against data), **M** =
strongly inferred from disassembly, **L** = tentative.
## Archive (IPFB `.pak`) subsystem
| Address | Name | Conf | Description |
|---|---|---|---|
| `0x824609C8` | `Pak_FindEntryByName` | H | Look up a TOC entry by path. Args `(r3 = pak object, r4 = char* path)`. Calls `Pak_HashPathName(path)`, then binary-searches the sorted 12-byte TOC (base `pak+4`, count `pak+8`, stride 12; compares the 32-bit `name_hash`). Returns the matching record pointer or 0. |
| `0x82460928` | `Pak_HashPathName` | H | Duplicate `r3 = char* path`, lowercase it in place (`Str_ToLowerAscii`), hash with `Sylph_NameHash`, free the copy, return the 32-bit hash. This is the path→key bridge. |
| `0x82455C78` | `Sylph_NameHash` | H | The IPFB TOC / cache-path name-hash. See [Name-hash](#name-hash-sylph_namehash). Input must already be lowercased. `r3 = char*``r3 = u32 hash`. |
| `0x825F4F90` | `Str_ToLowerAscii` | H | In-place ASCII lowercase (`A``Z``+0x20`); other bytes pass through. `r3 = char*`. (When `r3 == 0` it takes an unrelated init branch.) |
| `0x824607B0` | `Pak_IsIPFBHeader` | H | Validate an IPFB header. Loads the header's first word and checks it equals `"IPFB"` (`0x49504642`) via a delta trick: `first_word - 0x49504620 == 0x22` (`'B' - ' '`). `r5 = header ptr`. Returns bool-ish in `r3`. |
| `0x82460AD0`… | *(pak header parse, unregistered container)* | M | The pak-open/validate path around `0x82460DC0``0x82460EC4` builds an expected-header template (`"IPFB"`, `0x10000000` flags) on the stack and calls `Pak_IsIPFBHeader`. Function-boundary detection missed the enclosing frame (entry ≈ `0x82460E34`). |
| `0x82458508` | `Archive_StreamReadCrc32` | M | Streaming block reader that validates content with a reflected CRC-32 (init `0xFFFFFFFF`, final `~`, table at `g_Crc32Table`). Compares the computed CRC to a stored expected value (`state+144`). This is a **content-integrity** CRC, *not* the name-hash. |
| `0x828992F0` | `g_Crc32Table` (data) | H | 256-entry reflected CRC-32 lookup table. Referenced only by `Archive_StreamReadCrc32` and its sibling loop at `0x82457AF8`. |
## 3D resource subsystem
| Address | Name | Conf | Description |
|---|---|---|---|
| `0x82640290` | `Res3D_LoadMeshChunk` | L | 3D-resource loader: walks 12-byte records, checks chunk tags (`0x1A22AA26`, `0x2DA2AA24`), and copies `float` triples (x/y/z vertices) via `lfs`/`stfs`. Part of the DefTables/`machines\<model>\…` mesh path. |
## Name-hash (`Sylph_NameHash`)
Per-byte Barrett-reduced polynomial hash over the **lowercased** name:
```
A = 0 ; B = 0
for each (sign-extended) byte c of the lowercased name:
A = (A << 8) + c # 32-bit
A = A - (((A * 0x8003_1493) >> 32) rol 9 & 0x1FF) * 0x00FF_F9D7 # A mod 0x00FF_F9D7 (no final fixup)
B = B + c
hash = ((B & 0xFF) << 24) | (A & 0x00FF_FFFF)
```
- Modulus `0x00FF_F9D7`, reciprocal `0x8003_1493` (the `mulhwu`/`mullw` Barrett step).
- Low 24 bits = modular polynomial hash; top byte = 8-bit additive checksum of the bytes.
- No trailing conditional subtract — the value is defined by the exact op sequence.
- Faithful Rust reproduction: `sylpheed-formats/src/hash.rs` (`name_hash`).
**Verified** against retail TOCs: `name_hash("files.tbl") == 0x8342_1153`,
`name_hash("eng\\weapon.tbl") == 0x900C_8DCD`, `name_hash("eng\\strings.tbl") == 0x10C8_0B87`,
`name_hash("jpn\\weapon.tbl") == 0x9E85_FEFF`.
## TOC key path conventions (preimages)
The 32-bit TOC key is `name_hash` of a **backslash** path with the entry's
internal identity string. Confirmed schemes:
| Scheme | Example | Where |
|---|---|---|
| `unit\<ID>.tbl` | `unit\UN_f001_TCAF_DeltaSaber_T_EX5.tbl``0x7C96296C` | craft/ship entries in `GP_MAIN_GAME_*.pak` |
| `weapon\<ID>.tbl` | `weapon\Weapon_DSaber_P_wep_26_Missile.tbl` | weapon entries |
| `<lang>\<name>.tbl` | `eng\weapon.tbl`, `jpn\strings.tbl` | localized loadout/text tables |
| `<name>.tbl` | `files.tbl` | root manifest |
`<ID>` = the entry's internal `ID` field (IDXD string pool). Craft/weapon
entries also self-describe by content, so stats are readable without the key.
## Open threads
- **Defaulted IDXD fields** (`*Ratio`, the `*Count` family) carry no value on
disc. The large 16-byte-record binary node table inside a craft IDXD is
**spatial/mesh data**, not defaults (ruled out: it is not keyed by
`name_hash(field_key)`). Defaults must live in per-`schema_hash`
schema-definition tables (e.g. craft schema `0x43FAA517`) — location TBD.