← ClaudeAtlas

decomp-cpp-class-formlisted

Choose the C++ source form that makes mwccarm 2004/b56 emit what the SM64DS ROM actually contains - destructor variant order (D1/D0/D2), vtable and RTTI anchoring, constructor inlining, struct copies, bool widening, and virtual-vs-direct calls. Use when converting a shadow struct into a real C++ class, when D0/D1 are missing or emitted in the wrong order, when _ZTV/_ZTI is absent or multiply-defined, when a .c -> .cpp rename costs bytes, or when a class compiles but the whole-range link will not reproduce.
tangosdev/sm64ds-decomp · ★ 154 · API & Backend · score 80
Install: claude install-skill tangosdev/sm64ds-decomp
# Making mwccarm emit the ROM's shape Byte-matching a real C++ class is a question about **source form**, not about being "more correct". The compiler is an oracle — ask it rather than reasoning about the ABI. ## Ask the compiler, don't hand-mangle ```sh python tools/mangle.py candidate.cpp python tools/mangle.py candidate.cpp --expect _ZN5Actor8BehaviorEv python tools/mangle.py candidate.cpp --mangled-only --json ``` It compiles with the pinned 2004/b56 C++ flags and reads defined GLOBAL/WEAK ELF symbols, so substitutions, thunks, ctor/dtor variants and static data are the compiler's answer, not a guess. It uses `match.DEFAULT_FLAGS`, which differs from `rombuild.CFLAGS` (`-w illpragmas` vs `-Cpp_exceptions off`) — **verified not to change the emitted symbol set**, so it is sound for the checks below. **Ordering cannot be read from `st_value`.** mwccarm emits one `.text` section per function, so every symbol's `st_value` is 0. Order lives in the **section index**. ## Destructor variants: the form decides the order The ROM typically has **D1 then D0 and no D2** (e.g. ov045: D1 `0x021111a0` size 0x44, D0 `0x021111e4` size 0x58, landing exactly on the next function). Measured: | source form | instantiated in TU? | emits | order | |---|---|---|---| | `X::~X() {}` out of line | no | D2, D0, D1 + `_ZTV` | **D0 before D1** — wrong | | `X::~X() {}` out of line | yes (`new X()`) | D2, D0, D1 + `_ZTV` | **D0 before D1** — wrong | | `virtual ~X() {}` in class body | **no** | **