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>
4.9 KiB
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. 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, reciprocal0x8003_1493(themulhwu/mullwBarrett 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*Countfamily) 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 byname_hash(field_key)). Defaults must live in per-schema_hashschema-definition tables (e.g. craft schema0x43FAA517) — location TBD.