From c38d9b56283bef1d9b3dd5d8dd62d016d21c8013 Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sat, 14 Feb 2026 12:34:28 -0500 Subject: [PATCH] Tiny steps towards implementing C runtime --- decompile/Makefile | 21 ++++++++++++++++- decompile/objdiff.json | 8 +++---- decompile/src/XDK/CRT/CRT0.cpp | 32 ++++++++++++++++++++++++++ decompile/src/XDK/Win32.hpp | 4 ---- ghidra/ghidra_scripts/MSVC7Mangle.java | 12 ++++++---- ghidra/objects.csv | 2 +- 6 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 decompile/src/XDK/CRT/CRT0.cpp diff --git a/decompile/Makefile b/decompile/Makefile index 9ec36f4..fd0adf5 100644 --- a/decompile/Makefile +++ b/decompile/Makefile @@ -1,10 +1,27 @@ -all: src/JSRF/Jet2.obj +# JSRF Decompilation Makefile +# An NMAKE Makefile to compile the game with the Visual C++ 7.0 toolchain + +# All object files to link together +OBJ = src/JSRF/Jet2.obj src/JSRF/Core.obj src/JSRF/GameData.obj\ + src/XDK/CRT/CRT0.obj + + +# Linking into an executable; expect this to fail with undefined references +# until we've made at least stubs for everything in the game +#all: src/JSRF/Jet2.exe +#src/JSRF/Jet2.exe: $(OBJ) +# LINK.EXE /NOLOGO /NODEFAULTLIB /MERGE:.CRT=.data /OUT:$@ $** + +# For now, just compile all the object files +all: $(OBJ) + # Simple inference rule for producing object files .SUFFIXES: .cpp .obj .cpp.obj: CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< + # Header files used for each object src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/Std.hpp src/XDK/D3D.hpp\ src/XDK/Win32.hpp @@ -13,3 +30,5 @@ src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp src/Std.hpp\ src/XDK/D3D.hpp src/XDK/Win32.hpp src/JSRF/GameData.obj: src/JSRF/GameData.hpp + +src/XDK/CRT/CRT0.obj: src/XDK/Win32.hpp diff --git a/decompile/objdiff.json b/decompile/objdiff.json index e75b006..d7ccccf 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -14,10 +14,10 @@ "source_path": "src/JSRF/Jet2.cpp" }, "symbol_mappings": { - "?main_funcinfo@@3UFuncInfo@@A": "$T754", - "?main_handler@@YAXPAUEHExceptionRecord@@PAKPAXPAU_xDISPATCHER_CONTEXT@@@Z": "$L758", - "?main_handler_unwind1@@YAXXZ": "$L750", - "?main_unwindmap@@3PAUUnwindMapEntry@@A": "$T760", + "?main_funcinfo@@3UFuncInfo@@A": "$T745", + "?main_handler@@YAXPAUEHExceptionRecord@@PAKPAXPAU_xDISPATCHER_CONTEXT@@@Z": "$L749", + "?main_handler_unwind1@@YAXXZ": "$L741", + "?main_unwindmap@@3PAUUnwindMapEntry@@A": "$T751", "[.rdata-0]": "[.xdata$x-0]" } }, diff --git a/decompile/src/XDK/CRT/CRT0.cpp b/decompile/src/XDK/CRT/CRT0.cpp new file mode 100644 index 0000000..349b67f --- /dev/null +++ b/decompile/src/XDK/CRT/CRT0.cpp @@ -0,0 +1,32 @@ +/* JSRF Decompilation: XDK/CRT0.cpp +C runtime initialization. +Like other CRT code, there's some magic here with symbols that get special +treatment from the compiler and linker. +*/ + +#include "Win32.hpp" + + +// Every program is supposed to have a main(), so we can just assume its +// existence with a declaration here +int main(); + + + void __stdcall mainCRTStartup (); +static DWORD _mainXapiStartup(LPVOID lpThreadParameter); + + +// Address: 0x00148023 +// Matching: no +void __stdcall mainCRTStartup() { +/* The true entrypoint of the game, spawning a thread for the rest to run in +The linker automatically sets this function to the entrypoint. +*/ +} + +// Address: 0x00147FB4 +// Matching: no +DWORD _mainXapiStartup(LPVOID const lpThreadParameter) { +/* Runs some initialization and then calls main() */ + main(); +} diff --git a/decompile/src/XDK/Win32.hpp b/decompile/src/XDK/Win32.hpp index 1a9c0e3..ab72d1f 100644 --- a/decompile/src/XDK/Win32.hpp +++ b/decompile/src/XDK/Win32.hpp @@ -32,10 +32,6 @@ typedef int BOOL; // 64-bit integer compatibility type union LARGE_INTEGER { - struct { - DWORD LowPart; - LONG HighPart; - }; struct { DWORD LowPart; LONG HighPart; diff --git a/ghidra/ghidra_scripts/MSVC7Mangle.java b/ghidra/ghidra_scripts/MSVC7Mangle.java index 100165d..b62ed52 100644 --- a/ghidra/ghidra_scripts/MSVC7Mangle.java +++ b/ghidra/ghidra_scripts/MSVC7Mangle.java @@ -140,11 +140,15 @@ public class MSVC7Mangle extends GhidraScript{ /* Generate a mangled name for a function */ final String nameRaw = f.getName(true); - // Special case for main() - if (nameRaw.equals("main")) return "_main"; + // Internal symbols like intrinsics aren't mangled + if (nameRaw.startsWith("_")) return nameRaw; - // Special symbols like intrinsics aren't mangled - if (nameRaw.startsWith("__")) return nameRaw; + // Other special cases + switch (nameRaw) { + case "atexit": return "_atexit"; + case "main" : return "_main" ; + default : {} + } final ArrayList dict = new ArrayList<>(); diff --git a/ghidra/objects.csv b/ghidra/objects.csv index c7c3c82..04931b3 100644 --- a/ghidra/objects.csv +++ b/ghidra/objects.csv @@ -1,4 +1,4 @@ -Object,Delink?,.text,.text$XCU1,.text$XCU2,.text$x,D3D,DSOUND,MMATRIX,XGRPH,XPP,.rdata,.rdata$x,.data$CRT,.data,DOLBY +Object,Delink?,.text,.text$XC*1,.text$XC*2,.text$x,D3D,DSOUND,MMATRIX,XGRPH,XPP,.rdata,.rdata$x,.data$CRT,.data,DOLBY JSRF/Core.obj,true,0x00011000-0x00013FEB,,,0x00186BA0-0x00186C14,,,,,,0x001C4390-0x001C44F9,0x001E4D20-0x001E4DAB,,0x001EB880-0x001EB933, JSRF/GameData.obj,true,0x00039B50-0x0003B937,0x0018AD60-0x0018AD75,0x0018C9A0-0x0018C9AA,,,,,,,0x001CA16C-0x001CA3DB,,0x001EB790-0x001EB793,0x001EFC88-0x001F7047, JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620C-0x001E622F,,0x0022FCE0-0x0022FCE3,