From cbd63865e2c68b2c2cea533aa9d690b26ed68eaa Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 22 Feb 2026 10:37:59 -0500 Subject: [PATCH 1/3] Rename Smilebit library to MUSASHI Strings in the .rdata portion of the Smilebit in-house library code suggest that this was its name, with its contents having names beginning with an M (whence MMATRIX, for example). --- decompile/Makefile | 2 +- decompile/src/JSRF/Core.hpp | 2 +- decompile/src/{Smilebit => MUSASHI}/MMatrix.cpp | 0 decompile/src/{Smilebit => MUSASHI}/MMatrix.hpp | 0 ghidra/make_header.sh | 2 +- ghidra/objects.csv | 4 ++-- 6 files changed, 5 insertions(+), 5 deletions(-) rename decompile/src/{Smilebit => MUSASHI}/MMatrix.cpp (100%) rename decompile/src/{Smilebit => MUSASHI}/MMatrix.hpp (100%) diff --git a/decompile/Makefile b/decompile/Makefile index 966ec93..eb51c84 100644 --- a/decompile/Makefile +++ b/decompile/Makefile @@ -41,7 +41,7 @@ src/JSRF/Jet2.exe: $(OBJ) $(LIB) src/JSRF/Jet2.obj: src/JSRF/Core.hpp src/XDK/CRT/stddef.h src/XDK/D3D.h\ src/XDK/Win32.h -src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp\ +src/JSRF/Core.obj: src/JSRF/Core.hpp src/MUSASHI/MMatrix.hpp\ src/XDK/CRT/stddef.h src/XDK/D3D.h src/XDK/Win32.h src/JSRF/GameData.obj: src/JSRF/GameData.hpp diff --git a/decompile/src/JSRF/Core.hpp b/decompile/src/JSRF/Core.hpp index f335ed2..cc56748 100644 --- a/decompile/src/JSRF/Core.hpp +++ b/decompile/src/JSRF/Core.hpp @@ -5,7 +5,7 @@ Game and GameObj classes that form the foundation of the JSRF game code. #ifndef CORE_HPP #define CORE_HPP -#include "../Smilebit/MMatrix.hpp" +#include "../MUSASHI/MMatrix.hpp" #include "../XDK/CRT/stddef.h" #include "../XDK/D3D.h" #include "../XDK/Win32.h" diff --git a/decompile/src/Smilebit/MMatrix.cpp b/decompile/src/MUSASHI/MMatrix.cpp similarity index 100% rename from decompile/src/Smilebit/MMatrix.cpp rename to decompile/src/MUSASHI/MMatrix.cpp diff --git a/decompile/src/Smilebit/MMatrix.hpp b/decompile/src/MUSASHI/MMatrix.hpp similarity index 100% rename from decompile/src/Smilebit/MMatrix.hpp rename to decompile/src/MUSASHI/MMatrix.hpp diff --git a/ghidra/make_header.sh b/ghidra/make_header.sh index 6b772df..d2cae8a 100755 --- a/ghidra/make_header.sh +++ b/ghidra/make_header.sh @@ -11,7 +11,7 @@ HEADERS=" Std.hpp XDK/Win32.h XDK/D3D.h - Smilebit/MMatrix.hpp + MUSASHI/MMatrix.hpp JSRF/Core.hpp JSRF/GameData.hpp " diff --git a/ghidra/objects.csv b/ghidra/objects.csv index 5344983..6a7689b 100644 --- a/ghidra/objects.csv +++ b/ghidra/objects.csv @@ -5,12 +5,12 @@ JSRF/Jet2.obj,true,0x0006F9E0-0x0006FA6F,,,0x00187710-0x00187724,,,,,,,0x001E620 ADX (need to decompose),false,0x0013A570-0x0014555F,?,?,?,?,,,,,,?,?,?, Xapi (need to decompose),false,0x00145560-0x0014B79F,?,?,?,?,,,,,,?,?,?, XDK/Xapi/xapi0.obj,true,0x00147FB4-0x0014807C,,,,,,,,,,,,, -Smilebit libs (need to decompose),false,0x0014B7A0-0x0017BF3F,?,?,?,?,,,,,,?,?,?-0x0022ED2B, +Smilebit MUSASHI libs (need to decompose),false,0x0014B7A0-0x0017BF3F,?,?,?,?,,,,,,?,?,?-0x0022ED2B, C runtime (need to decompose),false,0x0017BF40-0x00182B80,?,?,?,,,,,?,?,0x0022ED2C-?,?,?, Unknown MS math lib,false,0x00182B81-0x0018694F,?,?,?,,,,,?,?,?,?,?, Another (tiny) Smilebit math lib,false,0x00186950-0x00186B7F,?,?,?,,,,,?,?,?,?,?, Direct3D8 (need to decompose),false,,?,,0x0018CB40-0x0019E334,,,,,?,?,?,?,?, DirectSound8 (need to decompose),false,,?,?,,,0x0019E340-0x001BA89B,,,,?,?,?,?,0x0027E080-0x00284E17 -Smilebit/MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13, +MUSASHI/MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13, Xgraphics (need to decompose),false,,?,,,,,0x001BBAC0-0x001BC7BB,,,,?,?,, XDK Peripherals (need to decompose),false,,?,,,,,,0x001BC7C0-0x001C3F57,,,?,?,, From 4e20347b7c6f83e694e13caefc9c621e6cc00c59 Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 22 Feb 2026 10:41:15 -0500 Subject: [PATCH 2/3] Decompile mainCRTStartup() Incidental changes include fixes for Xapi in the Makefille and objdiff.json, as well as new compiler flags for Xapi. --- decompile/Makefile | 8 ++++---- decompile/objdiff.json | 4 +++- decompile/src/XDK/Xapi/xapi0.c | 8 ++++---- readme.md | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/decompile/Makefile b/decompile/Makefile index eb51c84..1337f62 100644 --- a/decompile/Makefile +++ b/decompile/Makefile @@ -3,7 +3,7 @@ # All object files to link together OBJ = src/JSRF/Jet2.obj src/JSRF/Core.obj src/JSRF/GameData.obj\ - src/XDK/CRT/CRT0.obj + src/XDK/Xapi/xapi0.obj # Import library for the only thing we don't compile ourselves, the Xbox kernel LIB = lib/xboxkrnl.lib @@ -14,7 +14,7 @@ all: $(OBJ) # For now, just compile all the object files ## Build commands -.SUFFIXES: .cpp .obj .def .lib .exe.xbe +.SUFFIXES: .c .cpp .obj .def .lib .exe.xbe # Convert compiled executable into a working Xbox executable # (TODO: we may want to fork cxbe to add section checksums and the game ID) @@ -32,7 +32,7 @@ src/JSRF/Jet2.exe: $(OBJ) $(LIB) # Compile object files from source .c.obj: - CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< + CL.EXE /nologo /Wall /W4 /O1giy /Fo$@ /c $< .cpp.obj: CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< @@ -46,4 +46,4 @@ src/JSRF/Core.obj: src/JSRF/Core.hpp src/MUSASHI/MMatrix.hpp\ src/JSRF/GameData.obj: src/JSRF/GameData.hpp -src/XDK/CRT/CRT0.obj: src/XDK/Win32.h +src/XDK/Xapi/xapi0.obj: src/XDK/Win32.h diff --git a/decompile/objdiff.json b/decompile/objdiff.json index 4c6af55..573b0d4 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -1,6 +1,8 @@ { "custom_make": "NMAKE.EXE", "watch_patterns": [ + "*.c", + "*.h", "*.cpp", "*.hpp" ], @@ -53,4 +55,4 @@ } } ] -} \ No newline at end of file +} diff --git a/decompile/src/XDK/Xapi/xapi0.c b/decompile/src/XDK/Xapi/xapi0.c index ee9c93b..78bfefc 100644 --- a/decompile/src/XDK/Xapi/xapi0.c +++ b/decompile/src/XDK/Xapi/xapi0.c @@ -58,7 +58,7 @@ DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter) { } // Address: 0x00148023 -// Status: nonmatching +// Status: matching void mainCRTStartup(void) { /* The true entrypoint of the game, spawning a thread for the rest to run in The linker automatically sets this function to the entrypoint. @@ -66,11 +66,11 @@ The linker automatically sets this function to the entrypoint. HANDLE thread; // Figure out available thread-local storage - XapiTlsSize = ( + XapiTlsSize = 4 + (( (_tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData) + _tls_used.SizeOfZeroFill - ) + 15 & 0xFFFFFFF0; // Round up to nearest 0x10 - *_tls_used.AddressOfIndex = XapiTlsSize / (-4); + ) + 15 & 0xFFFFFFF0); // Round up to nearest 0x10 + *_tls_used.AddressOfIndex = -1 * XapiTlsSize/4; // Launch program as a thread thread = CreateThread(NULL, 0, mainXapiStartup, NULL, 0, NULL); diff --git a/readme.md b/readme.md index 49cfa1e..70ccc22 100644 --- a/readme.md +++ b/readme.md @@ -3,8 +3,8 @@ A matching decompilation of the Xbox game Jet Set Radio Future. ## Progress - Delinking progress: 1.03% (26559 out of 2574172 bytes in XBE address space) -- Decompilation progress: 18.5% (31 out of the 168 functions delinked so far) -- **Estimated total progress: 0.19%** (previous two multiplied together) +- Decompilation progress: 19.0% (32 out of the 168 functions delinked so far) +- **Estimated total progress: 0.20%** (previous two multiplied together) ## Roadmap The approach of this decompilation is to: From 823b19371ccdf6dcef61f226edcd4973fa8f6222 Mon Sep 17 00:00:00 2001 From: KeybadeBlox Date: Sun, 22 Feb 2026 14:04:18 -0500 Subject: [PATCH 3/3] Fully decompile xapi0 --- decompile/objdiff.json | 2 +- decompile/src/XDK/Xapi/xapi0.c | 103 ++++++++++++++++++++++++++++++--- readme.md | 2 +- 3 files changed, 97 insertions(+), 10 deletions(-) diff --git a/decompile/objdiff.json b/decompile/objdiff.json index 573b0d4..083041a 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -50,7 +50,7 @@ "target_path": "target/XDK/Xapi/xapi0.obj", "base_path": "src/XDK/Xapi/xapi0.obj", "metadata": { - "complete": false, + "complete": true, "source_path": "src/XDK/Xapi/xapi0.c" } } diff --git a/decompile/src/XDK/Xapi/xapi0.c b/decompile/src/XDK/Xapi/xapi0.c index 78bfefc..d726005 100644 --- a/decompile/src/XDK/Xapi/xapi0.c +++ b/decompile/src/XDK/Xapi/xapi0.c @@ -21,11 +21,14 @@ extern struct IMAGE_TLS_DIRECTORY { DWORD SizeOfZeroFill; DWORD Characteristics; } _tls_used; +extern int _tls_array; +extern int _tls_index; extern int XapiTlsSize; DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter); -BOOL __stdcall CloseHandle (HANDLE hHandle ); +void __stdcall XapiInitProcess(void); +BOOL __stdcall CloseHandle (HANDLE hHandle); typedef DWORD (__stdcall * LPTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); HANDLE __stdcall CreateThread( @@ -43,18 +46,102 @@ void __stdcall XapiBootToDash( DWORD dwParameter2 ); +void __stdcall _rtinit(void); +void __stdcall _cinit (void); + // Every program is supposed to have a main(), so we can just assume its -// existence with a declaration here -int main(void); +// existence with a declaration here. Interestingly, it's called with +// arguments here despite being declared without any on the developer's side. +int main( + int argc, + char * * argv, + char * * envp +); // Address: 0x00147FB4 -// Status: unimplemented -DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter) { -/* Runs some Xbox-specific initialization and then calls main() */ - main(); - return 0; +// Status: matching +__declspec(naked) DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter) { +/* Runs some Xbox-specific initialization and then calls main() +It appears to be truly impossible in Visual C++ 7.0 to access the FS register +without writing assembly, and also for inline assembly to write to a variable +in a register rather than on the stack. Thus, the only apparent way to make +the middle part of the function match is through writing the instructions +directly. Given that the C parts of this function are so simple that a human +and a compiler would reasonably produce the exact same code, and this function +exhibits other oddities mentioned in the body, it's likely this whole function +was originally written purely in assemblys. In the spirit of decompilation, +however, we'll lift what we can into C. +*/ + XapiInitProcess(); + + // Honestly unsure what's being done here, as FS doesn't seem to follow + // the same structure as 32-bit Windows + __asm { + mov eax, fs:[0x20] + mov eax, [eax+0x250] + test eax, eax + je zero + mov ecx, [eax+0x24] + jmp store + + /* + All this jumping around is strange, as it could easily be a + single branch, which is very plain to see if written out as C + (in fact, while MSVC's behaviour hasn't been tested, it + wouldn't take a very smart compiler to optimize this out if it + was written this way in C). It seems likely this is awkward + human-written assembly. + */ + zero: + xor ecx, ecx + + store: + test ecx, ecx + je end + + /* + This section is suspect because of how it preserves edi despite + it not being used anywhere else, as if it was a separately + written function. If it was a function, it must have been + inlined, but it couldn't be because it must be called from + assembly to use the value in ecx that never went on the stack + (as passing data from C to assembly has to do). Notably, this + function's calling convention does require edi to be preserved, + but if left up to the compiler, it will push and pop edi in the + prologue and epilogue, not here (which this function must be + declared as naked to avoid). + + It may be that this function was originally written entirely in + assembly and declared naked, with the author deciding to + preserve edi only in this one section using it. + */ + push edi + mov eax, fs:[0x28] + mov edi, fs:[_tls_array] + mov edx, [_tls_index] + mov edx, [edi + edx*0x4] + sub edx, [eax + 0x28] + mov byte ptr [ecx], 0x1 + add edx, _tls_array + mov [ecx + 0x4], edx + pop edi + + end: + }; + + _rtinit(); + _cinit(); + main(0, NULL, NULL); + + XapiBootToDash(XLD_LAUNCH_DASHBOARD_ERROR, XLD_ERROR_INVALID_XBE, 0); + + // Return 0 to satisfy signature required for thread functions + _asm { + xor eax, eax + ret 4 + }; } // Address: 0x00148023 diff --git a/readme.md b/readme.md index 70ccc22..25abed9 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ A matching decompilation of the Xbox game Jet Set Radio Future. ## Progress - Delinking progress: 1.03% (26559 out of 2574172 bytes in XBE address space) -- Decompilation progress: 19.0% (32 out of the 168 functions delinked so far) +- Decompilation progress: 19.6% (33 out of the 168 functions delinked so far) - **Estimated total progress: 0.20%** (previous two multiplied together) ## Roadmap