diff --git a/decompile/Makefile b/decompile/Makefile index 1337f62..966ec93 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/Xapi/xapi0.obj + src/XDK/CRT/CRT0.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: .c .cpp .obj .def .lib .exe.xbe +.SUFFIXES: .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 /O1giy /Fo$@ /c $< + CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< .cpp.obj: CL.EXE /nologo /Wall /W4 /Ogityb0 /GfX /Fo$@ /c $< @@ -41,9 +41,9 @@ 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/MUSASHI/MMatrix.hpp\ +src/JSRF/Core.obj: src/JSRF/Core.hpp src/Smilebit/MMatrix.hpp\ src/XDK/CRT/stddef.h src/XDK/D3D.h src/XDK/Win32.h src/JSRF/GameData.obj: src/JSRF/GameData.hpp -src/XDK/Xapi/xapi0.obj: src/XDK/Win32.h +src/XDK/CRT/CRT0.obj: src/XDK/Win32.h diff --git a/decompile/objdiff.json b/decompile/objdiff.json index 083041a..4c6af55 100644 --- a/decompile/objdiff.json +++ b/decompile/objdiff.json @@ -1,8 +1,6 @@ { "custom_make": "NMAKE.EXE", "watch_patterns": [ - "*.c", - "*.h", "*.cpp", "*.hpp" ], @@ -50,9 +48,9 @@ "target_path": "target/XDK/Xapi/xapi0.obj", "base_path": "src/XDK/Xapi/xapi0.obj", "metadata": { - "complete": true, + "complete": false, "source_path": "src/XDK/Xapi/xapi0.c" } } ] -} +} \ No newline at end of file diff --git a/decompile/src/JSRF/Core.hpp b/decompile/src/JSRF/Core.hpp index cc56748..f335ed2 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 "../MUSASHI/MMatrix.hpp" +#include "../Smilebit/MMatrix.hpp" #include "../XDK/CRT/stddef.h" #include "../XDK/D3D.h" #include "../XDK/Win32.h" diff --git a/decompile/src/MUSASHI/MMatrix.cpp b/decompile/src/Smilebit/MMatrix.cpp similarity index 100% rename from decompile/src/MUSASHI/MMatrix.cpp rename to decompile/src/Smilebit/MMatrix.cpp diff --git a/decompile/src/MUSASHI/MMatrix.hpp b/decompile/src/Smilebit/MMatrix.hpp similarity index 100% rename from decompile/src/MUSASHI/MMatrix.hpp rename to decompile/src/Smilebit/MMatrix.hpp diff --git a/decompile/src/XDK/Xapi/xapi0.c b/decompile/src/XDK/Xapi/xapi0.c index d726005..ee9c93b 100644 --- a/decompile/src/XDK/Xapi/xapi0.c +++ b/decompile/src/XDK/Xapi/xapi0.c @@ -21,14 +21,11 @@ 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); -void __stdcall XapiInitProcess(void); -BOOL __stdcall CloseHandle (HANDLE hHandle); +BOOL __stdcall CloseHandle (HANDLE hHandle ); typedef DWORD (__stdcall * LPTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); HANDLE __stdcall CreateThread( @@ -46,106 +43,22 @@ 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. 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 -); +// existence with a declaration here +int main(void); // Address: 0x00147FB4 -// 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 - }; +// Status: unimplemented +DWORD __stdcall mainXapiStartup(LPVOID lpThreadParameter) { +/* Runs some Xbox-specific initialization and then calls main() */ + main(); + return 0; } // Address: 0x00148023 -// Status: matching +// Status: nonmatching 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. @@ -153,11 +66,11 @@ The linker automatically sets this function to the entrypoint. HANDLE thread; // Figure out available thread-local storage - XapiTlsSize = 4 + (( + XapiTlsSize = ( (_tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData) + _tls_used.SizeOfZeroFill - ) + 15 & 0xFFFFFFF0); // Round up to nearest 0x10 - *_tls_used.AddressOfIndex = -1 * XapiTlsSize/4; + ) + 15 & 0xFFFFFFF0; // Round up to nearest 0x10 + *_tls_used.AddressOfIndex = XapiTlsSize / (-4); // Launch program as a thread thread = CreateThread(NULL, 0, mainXapiStartup, NULL, 0, NULL); diff --git a/ghidra/make_header.sh b/ghidra/make_header.sh index d2cae8a..6b772df 100755 --- a/ghidra/make_header.sh +++ b/ghidra/make_header.sh @@ -11,7 +11,7 @@ HEADERS=" Std.hpp XDK/Win32.h XDK/D3D.h - MUSASHI/MMatrix.hpp + Smilebit/MMatrix.hpp JSRF/Core.hpp JSRF/GameData.hpp " diff --git a/ghidra/objects.csv b/ghidra/objects.csv index 6a7689b..5344983 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 MUSASHI libs (need to decompose),false,0x0014B7A0-0x0017BF3F,?,?,?,?,,,,,,?,?,?-0x0022ED2B, +Smilebit 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 -MUSASHI/MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13, +Smilebit/MMatrix.obj,false,,?,,,,0x001BA8A0-0x001BBAAF,,,,,?,?,0x00264BD8-0x00264C13, Xgraphics (need to decompose),false,,?,,,,,0x001BBAC0-0x001BC7BB,,,,?,?,, XDK Peripherals (need to decompose),false,,?,,,,,,0x001BC7C0-0x001C3F57,,,?,?,, diff --git a/readme.md b/readme.md index 25abed9..49cfa1e 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: 19.6% (33 out of the 168 functions delinked so far) -- **Estimated total progress: 0.20%** (previous two multiplied together) +- Decompilation progress: 18.5% (31 out of the 168 functions delinked so far) +- **Estimated total progress: 0.19%** (previous two multiplied together) ## Roadmap The approach of this decompilation is to: