Files
SalastilandClaude Opus 5.5 b1cc8a1b0d Keep only symbol names proven from the shipped binary
Drop the names taken from an external offset header (functions and
globals), keeping only names the binary itself proves: _WinMain@16 from
the CRT entry call, and Class::Method names from the client's own log
strings. The six functions Ghidra missed stay in the map under neutral
FUN_ names, justified by vtable/pointer references. NAMES.md, README
and ROADMAP no longer point at third-party offset lists.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 23:01:25 -04:00

101 lines
4.5 KiB
Markdown

# EverQuest Decomp/Recomp
A byte-for-byte matching decompilation of the EverQuest **Titanium** client
(`eqgame.exe`, linked 2005-10-31 18:36:26 UTC). The goal is C++ source that
recompiles with the original toolchain to the exact same machine code, which
can then be ported, fixed and recompiled freely.
This repository contains **no original binaries or game assets**, only decompiled source and tools. You need your own copy of the
client; the tools check it against the expected hash.
| | |
|---|---|
| Target | `eqgame.exe`, SHA1 `e8fdc68b46df69dde0094d57fd7ba2cb33aef1c5` |
| Compiler | MSVC 7.1 (Visual Studio .NET 2003), `cl` 13.10.3077, run under Wine |
| Flags so far | `/O1 /GX /GS` (size-optimised, EH, stack cookies; confirmed by matching code) |
| Functions | ~15.3k found by Ghidra: ~8.4k game code, ~6.9k CRT/STL/library |
## Setup
Requirements: Linux (or WSL/macOS) with `wine`, `python3` + PyYAML, `ninja`,
`i686-w64-mingw32-objdump` (binutils for mingw), and optionally Ghidra.
```sh
tools/setup.sh /path/to/EverQuest/eqgame.exe # links orig/, fetches MSVC 7.1, verifies both
python3 tools/eq.py build # compile src/ -> build/obj/
python3 tools/eq.py check # compare against the original
python3 tools/eq.py progress
```
## Workflow
1. Pick a function: `python3 tools/eq.py todo` lists unmatched game functions,
smallest first. `build/decomp/<addr>.c` has Ghidra's pseudo-C for it
(`tools/ghidra/ExportDecomp.java`), and `python3 tools/eq.py diff 0x00401050`
shows the disassembly.
2. Write C++ under `src/`, with an annotation directly above each definition:
```cpp
// FUNCTION: EQGAME 0x00401050
void CList::Append(CListNode* node) { ... }
// GLOBAL: EQGAME 0x0079c100
CSpellPointManager* g_pSpellPointManager;
```
Annotations on declarations (`extern` globals, called functions) tell the checker
where referenced symbols live. `// LIBRARY: EQGAME 0xADDR mangled` names CRT
helpers (see `include/crt_symbols.h`). Add `NONMATCHING` after the address for
code that is functionally right but not yet byte-exact.
3. `python3 tools/eq.py build && python3 tools/eq.py check`. The tools pair each
annotation with the compiled (mangled) symbol, so there's no need to edit
`symbols.txt` by hand.
4. Iterate with `diff` until `check` says `MATCH`.
5. `python3 tools/eq.py link` rebuilds `build/eqgame.exe` from the compiled objects
and checks its SHA1 against the original. It also prints how much of the
binary now comes from source. See [docs/ROADMAP.md](docs/ROADMAP.md).
### Check statuses
| Status | Meaning |
|---|---|
| `MATCH` | every byte equal, every relocation points at the right symbol |
| `MATCH?` | bytes equal, but some referenced symbols have no address yet (annotate them, or `check --learn`) |
| `NONMAT` | marked `NONMATCHING`, still differs |
| `BADREF` | bytes equal, but a call/global resolves to a different address than the map says |
| `DIFF` | code differs |
Relocated fields (calls, globals, string literals) are masked when comparing
bytes and then verified separately: against the symbol map for named symbols,
and by content for string literals and float constants.
## Layout
```
config/eqgame/config.yaml target hash, compiler flags
config/eqgame/symbols.txt ADDR SIZE KIND NAME for every known function/global
src/ decompiled source (one .cpp per original translation unit, eventually)
include/ shared headers
tools/eq.py build / check / diff / progress / map
tools/binfmt.py PE + COFF readers
tools/cl.sh MSVC 7.1 under Wine
tools/ghidra/ headless export used to seed symbols.txt
orig/ your eqgame.exe (git-ignored)
```
Per-file compiler flags: put `// CFLAGS: /O2` (etc.) near the top of a source file.
### Re-seeding the symbol map from Ghidra
```sh
/opt/ghidra/support/analyzeHeadless build/ghidra eqgame -import orig/eqgame.exe \
-scriptPath tools/ghidra -postScript ExportFunctions.java "$PWD/build/ghidra_functions.txt"
python3 tools/eq.py import-ghidra build/ghidra_functions.txt # keeps existing names
```
## Notes
- The Rich header shows ~640 C++ objects from cl 13.10.3077, plus libraries built
with VC6 (build 8447/9178), likely Miles Sound System, DirectX helpers, etc.
Those are classified as `lib` and excluded from progress.
- Names are placeholders until identified from the binary itself (its own log
strings and code structure); see `config/eqgame/NAMES.md`.