Getting Tekken Tag Tournament 2 to work with the tools
Documenting my process for getting ttt2 recompiled for others to see, it might be of help for other games (i know nothing about x360 modding and it's my first time reading powerpc instructions, i come from an x86 background.) If you know what you're doing you'll get further with this project than me, feel free to use this as a reference
anyway, the analyzer tries to scan for switch tables using the following instructions (sonic unleashed uses this pattern before the tables):
PPC_INST_LIS,
PPC_INST_ADDI,
PPC_INST_RLWINM, // SLWI alias
PPC_INST_LWZX,
PPC_INST_MTCTR,
PPC_INST_BCTR
where as in tag 2 (and probably other games) it's:
PPC_INST_LIS,
PPC_INST_RLWINM, // SLWI alias
PPC_INST_ADDI,
PPC_INST_LWZX,
PPC_INST_MTCTR,
PPC_INST_BCTR
ADDI and RLWINM are swapped, so changing the values in absoluteSwitch to:
uint32_t absoluteSwitch[] =
{
PPC_INST_LIS,
PPC_INST_RLWINM, // (slwi alias)
PPC_INST_ADDI,
PPC_INST_LWZX,
PPC_INST_MTCTR,
PPC_INST_BCTR
};
and adjusting the ReadTable function to properly offset the instructions from:
auto* code = (uint32_t*)image.Find(table.base);
ppc::Disassemble(code, table.base, insn);
pOffset = insn.operands[1] << 16;
ppc::Disassemble(code + 1, table.base + 4, insn);
pOffset += insn.operands[2];
to
auto* code = (uint32_t*)image.Find(table.base);
ppc::Disassemble(code, table.base, insn); // lis
pOffset = insn.operands[1] << 16; // Upper 16 bits
ppc::Disassemble(code + 2, table.base + 8, insn); // addi (skip rlwinm at +4)
pOffset += insn.operands[2]; // Lower 16 bits
now we're getting a proper switch table, here's an example:
[[switch]]
base = 0x822537A4
r = 11
default = 0x82253868
labels = [
0x82253854,
0x82253868,
0x82253854,
0x82253854,
0x82253868,
0x82253854,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253854,
0x82253868,
0x82253868,
0x82253854,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253868,
0x82253854,
0x82253868,
0x82253868,
0x82253868,
0x82253854,
0x82253868,
0x82253854,
0x82253868,
0x82253854,
0x82253868,
0x82253868,
0x82253854,
]
...
looks perfect to what we see in r2:
[0x822400ec]> /x 7c0903a6 @ 0x82240000..0x82da0000
0x82253fb4 hit9_0 7c0903a6
0x82254214 hit9_1 7c0903a6
0x822545b0 hit9_2 7c0903a6
0x822550b0 hit9_3 7c0903a6
0x82255890 hit9_4 7c0903a6
0x82268f1c hit9_5 7c0903a6
0x8226c000 hit9_6 7c0903a6
...
[0x822400ec]> s hit9_0
[0x82253fb4]> pd 10
│ ;-- hit0_0:
│ ;-- hit9_0:
│ 0x82253fb4 7c0903a6 mtctr r0
│ 0x82253fb8 4e800420 bctr
0x82253fbc .dword 0x82253854 ; aav.0x82253854 # Wow!
0x82253fc0 .dword 0x82253868 ; aav.0x82253868
0x82253fc4 .dword 0x82253854 ; aav.0x82253854
0x82253fc8 .dword 0x82253854 ; aav.0x82253854
0x82253fcc .dword 0x82253868 ; aav.0x82253868
0x82253fd0 .dword 0x82253854 ; aav.0x82253854
0x82253fd4 .dword 0x82253868 ; aav.0x82253868
0x82253fd8 .dword 0x82253868 ; aav.0x82253868
[0x82253fb4]>
Now for the config toml file, here's the bare minimum I got to make it generate the recompiled files without getting a segfault:
[main]
file_path = "Default_unpacked.xex"
out_directory_path = "ppc"
switch_table_file_path = "jump_tables.toml"
restgprlr_14_address = 0x82bafea0
savegprlr_14_address = 0x82bafe50
restfpr_14_address = 0x82bb0b3c
savefpr_14_address = 0x82bb0af0
restvmx_14_address = 0x82bb1d58
savevmx_14_address = 0x82bb1ac0
savevmx_64_address = 0x82bb1b54
restvmx_64_address = 0x82bb1dec
Getting the rest/save addresses is pretty straight forward: https://github.com/hedge-dev/XenonRecomp/tree/main?tab=readme-ov-file#register-restore--save-functions
Right now i'm stuck at trying to get it compiled without anything special, just the raw ppc files themselves as a test. i'm getting errors for: "error: use of undeclared label 'loc_82BAFE5C'" in lots of places, XenonRecomp did warn me about switch cases jumping out of functions like:
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAC64
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAC64
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAC64
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAC64
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAB58
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAC64
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAAA8
ERROR: Switch case at 822FA970 is trying to jump outside function: 822FAAC4
and also some unrecognized instructions:
Unrecognized instruction at 0x82D6E3B8: lhzu
Unrecognized instruction at 0x82D6E3BC: sthu
Unrecognized instruction at 0x82D6E3DC: lhzu
Unrecognized instruction at 0x82D6E3E0: sthu
Unrecognized instruction at 0x82D6E3FC: lhzu
Unrecognized instruction at 0x82D6E400: sthu
Unrecognized instruction at 0x82D6E41C: lhzu
Unrecognized instruction at 0x82D6E420: sthu
Unrecognized instruction at 0x82D6E43C: lhzu
Unrecognized instruction at 0x82D6E440: sthu
Unrecognized instruction at 0x82D6E45C: lhzu
Unrecognized instruction at 0x82D6E460: sthu
Unrecognized instruction at 0x82D6E47C: lhzu
Unrecognized instruction at 0x82D6E480: sthu
Unrecognized instruction at 0x82D6E49C: lhzu
Unrecognized instruction at 0x82D6E4A0: sthu
For now I gotta edit the analyzer to account for the function boundaries because I really don't wanna do it manually so i'll update here if I get anything working
https://github.com/hedge-dev/XenonRecomp/issues/38#issuecomment-2698394064
Following this, I'm attempting to do the same for Silent Hill Downpour, and using the BBB_MoreInstructions branch, I'm down to a handful of unique errors when running XenonRecomp.
XenonAnalyse didn't generate the switch tables using the default pattern, so I've only got the absolute table to show up from using your guide here. I also had to modify the compression of the .xex using XeXTool for XenonAnalyse to accept it.
Unrecognized instruction at 0x823588B0: mulhd
Unrecognized instruction at 0x823AF9B8: vpkuwus128
Unrecognized instruction at 0x825256F8: frsqrte
Unrecognized instruction at 0x831AF414: vnor128
vcmpbfp128. at 8324F068 has RC bit enabled but no comparison was generated
ERROR: Switch case at 8312944C is trying to jump outside function: 8312948C
Here's my full log:
Following this, I'm attempting to do the same for Silent Hill Downpour, and using the
BBB_MoreInstructionsbranch, I'm down to a handful of unique errors when running XenonRecomp.XenonAnalyse didn't generate the switch tables using the default pattern, so I've only got the absolute table to show up from using your guide here. I also had to modify the compression of the .xex using XeXTool for XenonAnalyse to accept it.
Unrecognized instruction at 0x823588B0: mulhd Unrecognized instruction at 0x823AF9B8: vpkuwus128 Unrecognized instruction at 0x825256F8: frsqrte Unrecognized instruction at 0x831AF414: vnor128 vcmpbfp128. at 8324F068 has RC bit enabled but no comparison was generated ERROR: Switch case at 8312944C is trying to jump outside function: 8312948CHere's my full log:
case PPC_INST_VNOR128:
println("\t_mm_store_si128((__m128i*){}.u8, _mm_xor_si128(_mm_or_si128(_mm_load_si128((__m128i*){}.u8), _mm_load_si128((__m128i*){}.u8)), _mm_set1_epi32(0xFFFFFFFF)));", v(insn.operands[0]), v(insn.operands[1]), v(insn.operands[2]));
break;
case PPC_INST_MULHD:
println("\t{}.s64 = (int64_t({}.s32) * int64_t({}.s32)) >> 32;", r(insn.operands[0]), r(insn.operands[1]), r(insn.operands[2]));
break;
I haven't looked into frsqrte and vpkuwus128 but i added other instructions (including the BBB ones) in my fork: https://github.com/DennisStanistan/XenonRecomp/commit/3f02123e7e773418113650bc31f8c9cc12f59b75 - use it with a grain of salt, i had to resort to LLMs that read powerpc pdfs to figure out anything after PPC_INST_MULHD in the code (including PPC_INST_MULHD itself) lol
I'm still trying to figure out function boundaries to prevent goto's to labels that are outside of function scopes but i'm having powerpc comprehension issues atm
Can confirm, mulhd and vnor128 logs have disappeared with your fork.
I did implement the others yesterday on a local branch like you have, but I think the biggest blockade right now is the jumping issue. I can't figure that one out at all sadly.
I've added a bunch of function boundary checks which eliminated the ERROR: Switch case at { } is trying to jump outside function: { }
I also had some problematic loc_ variables, so I just used the function boundary technique on them too, and they're also gone - meaning I can compile all of my .cpp files.
Here's how mine look like for reference:
functions = [
{ address = 0x8240AF58, size = 0xD8 },
{ address = 0x82428808, size = 0x84 },
{ address = 0x82488D70, size = 0x10C },
{ address = 0x827757C0, size = 0x13C },
{ address = 0x829CC508, size = 0xDC },
{ address = 0x829E3828, size = 0x258 },
{ address = 0x82CF2DE8, size = 0x1A8 },
{ address = 0x82D96F90, size = 0x120 },
{ address = 0x82D971E8, size = 0xCC },
{ address = 0x82DCC668, size = 0xDC },
{ address = 0x83129430, size = 0x10C },
{ address = 0x83081BF8, size = 0x25C },
{ address = 0x830522E8, size = 0xB0 },
{ address = 0x82D972B8, size = 0x258 },
]
invalid_instructions = [
{ data = 0x00000000, size = 4 }, # Padding
]
Now I'm getting linker errors everywhere, all pointing to stuff like this:
1>lld-link : error : undefined symbol: void __cdecl __imp__RtlInitializeCriticalSection(struct PPCContext &__restrict, unsigned char *)
1>>>> referenced by SH8_PC\x64\Debug\ppc_func_mapping.obj:(struct PPCFuncMapping *PPCFuncMappings)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.102.cpp:6369
1>>>> SH8_PC\x64\Debug\ppc_recomp.102.obj:(__declspec(dllimport) _sub_82A66228)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.102.cpp:6404
1>>>> SH8_PC\x64\Debug\ppc_recomp.102.obj:(__declspec(dllimport) _sub_82A66228)
1>>>> referenced 49 more times
1>
1>lld-link : error : undefined symbol: void __cdecl __imp__RtlEnterCriticalSection(struct PPCContext &__restrict, unsigned char *)
1>>>> referenced by SH8_PC\x64\Debug\ppc_func_mapping.obj:(struct PPCFuncMapping *PPCFuncMappings)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:1595
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82300A78)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:20833
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82308C80)
1>>>> referenced 385 more times
1>
1>lld-link : error : undefined symbol: void __cdecl __imp__RtlTryEnterCriticalSection(struct PPCContext &__restrict, unsigned char *)
1>>>> referenced by SH8_PC\x64\Debug\ppc_func_mapping.obj:(struct PPCFuncMapping *PPCFuncMappings)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:1586
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82300A78)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:20824
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82308C80)
1>>>> referenced 94 more times
1>
1>lld-link : error : undefined symbol: void __cdecl __imp__RtlLeaveCriticalSection(struct PPCContext &__restrict, unsigned char *)
1>>>> referenced by SH8_PC\x64\Debug\ppc_func_mapping.obj:(struct PPCFuncMapping *PPCFuncMappings)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:1626
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82300A78)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.0.cpp:20847
1>>>> SH8_PC\x64\Debug\ppc_recomp.0.obj:(__declspec(dllimport) _sub_82308C80)
1>>>> referenced 433 more times
1>
1>lld-link : error : undefined symbol: void __cdecl __imp__KeTlsAlloc(struct PPCContext &__restrict, unsigned char *)
1>>>> referenced by SH8_PC\x64\Debug\ppc_func_mapping.obj:(struct PPCFuncMapping *PPCFuncMappings)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.189.cpp:18253
1>>>> SH8_PC\x64\Debug\ppc_recomp.189.obj:(__declspec(dllimport) _sub_82FEDC58)
1>>>> referenced by E:\Projects\Xenon\XenonRecomp\out\build\x64-Clang-Debug\XenonRecomp\ppc\ppc_recomp.199.cpp:4097
1>>>> SH8_PC\x64\Debug\ppc_recomp.199.obj:(__declspec(dllimport) _sub_830845B8)
1>>>> referenced 4 more times
I think it might be related to this particular thing? - not sure how to proceed from here, tbh.