Xenonrecomp
XenonRecomp est un outil qui convertit les exécutables Xbox 360 en code C++, qui peut ensuite être recompilé pour n'importe quelle plateforme. Ce projet a été...
Choisir une liste...
XenonRecomp
XenonRecomp est un outil qui convertit les exécutables Xbox 360 en code C++, qui peut ensuite être recompilé pour n'importe quelle plateforme.
Ce projet a été fortement inspiré parN64: Recompiled, un outil similaire pour les exécutables N64.
- OUICe projet ne prévoit pas de mise en œuvre au moment de l'exécution. Il convertit uniquement le code de jeu en C++, qui ne fonctionnera pas correctement sans un support d'exécution.Faire fonctionner le jeu est votre responsabilité.
Détails de mise en œuvre
Instructions
Les instructions sont directement converties sans aucun effort pour les faire ressembler au code décompilé, ce qui signifie que la sortie n'est pas très lisible par l'homme. L'état CPU est passé comme argument à chaque fonction PPC, qui comprend des définitions pour chaque registre PPC et leurs valeurs actuelles au moment de l'exécution. Le second argument est le pointeur d'adresse de base, car le processeur Xbox 360 utilise des pointeurs 32 bits.
Une bonne quantité d'instructions PPC sont mises en œuvre, les instructions manquantes étant principalement des variantes d'instructions déjà mises en œuvre. Certaines instructions, comme celles du D3D, ne prennent pas en charge tous les types d'opérandes. Lorsqu'un cas manquant est rencontré, un avertissement est généré, ou une pause de débogage est insérée dans le code C++ converti.
Les implémentations d'instruction fonctionnent sur des valeurs peu endiennes. Cependant, puisque la Xbox 360 est une machine grand-endienne, les instructions de chargement de mémoire échangent l'endianité lors de la lecture des valeurs, et les instructions de stockage de mémoire l'inversent à grand-endian avant d'écrire. Toutes les charges de mémoire et les magasins sont marqués volatiles pour empêcher Clang de faire un réordre de code dangereux.
La manipulation de l'endianité des registres vectoriaux est plus compliquée. Au lieu d'échanger des éléments individuels 32 bits, le recompilateur choisit d'inverser l'ensemble du vecteur 16 octets. Les instructions doivent tenir compte de cet ordre inversé, comme l'utilisation des composants WZY au lieu de XYZ dans les produits point ou l'exigence d'arguments inversés pour les instructions vectoriels.
Le FPU s'attend à ce que les nombres dénormalisés restent non modifiés, tandis que les instructions VMX les chassent toujours. Ceci est géré en stockant l'état du point flottant courant dans la structure de l'état CPU et en permettant ou en désactivant un rinçage dénormal si nécessaire avant d'exécuter chaque instruction.
La plupart des instructions VMX sont implémentées en utilisant x86 intrinsèques. Le soutien à ARM64 est mis en œuvre en utilisantSIMD Everywhere.
MMIO
MMIO, qui est généralement utilisé pour les opérations matérielles telles que le décodage XMA, n'est actuellement pas mis en œuvre. Il y a une tentative inachevée de mettre en oeuvre le MMIO, mais le soutenir peut être non-trivial et pourrait nécessiter une analyse avancée des instructions.
Fonctions indirectes
Les appels de fonctions virtuelles sont résolus en créant une « table de hachage parfaite » à l'exécution, où le déréférencement d'un pointeur 64 bits (en utilisant l'adresse d'instruction originale multipliée par 2) donne l'adresse de la fonction recompilée. Ceci a été précédemment mis en œuvre en créant une allocation virtuelle de 8 Go, mais il avait trop de pression mémoire. Maintenant, il compte sur les adresses de fonction placées après la région de mémoire XEX valide dans le pointeur de mémoire de base. Ces régions sont exportées sous forme de macros dans la productionppc_config.hfichier.
Sauter les tables
Les tables de saut, au moins dans les anciens binaires Xbox 360, ont souvent des modèles d'assemblage prévisibles, ce qui les rend faciles à détecter statiquement sans avoir besoin d'une machine virtuelle. XenonAnalyse a une logique pour détecter les tables de saut dans Sonic Unleashed, bien que les variations d'autres jeux (probablement dues aux mises à jour du compilateur Xbox 360) peuvent nécessiter des modifications de la logique de détection. Actuellement, il n'y a pas de solution entièrement générique pour gérer les tables de saut, de sorte que des mises à jour de la logique de détection peuvent être nécessaires pour d'autres jeux.
La façon typique de trouver des tables de saut est en cherchant lamtctr r0l'enseignement. Il sera presque toujours suivi avec unbctr, avec les instructions précédentes calculant l'adresse de saut.
XenonAnalyse génère un fichier TOML contenant des tables de saut détectées, qui peut être référencé dans le fichier de configuration principal de TOML. Cela permet au recompilateur de générer de véritables cas de commutation pour ces tables de saut.
Analyse des limites des fonctions
XenonAnalyse comprend un analyseur de limites de fonction qui fonctionne bien dans la plupart des cas. Les fonctions avec espace de pile ont leurs limites définies dans la.pdatasegment du XEX. Pour les fonctions qui ne se trouvent pas dans ce segment, l'analyseur détecte le début des fonctions en recherchant des instructions de liaison de branche et détermine leur longueur par analyse statique.
Cependant, l'analyseur lutte avec les fonctions contenant des tables de saut, puisqu'elles ressemblent à des appels de queue sans suffisamment d'informations. Bien qu'il n'y ait actuellement aucune solution pour cela, il pourrait être relativement simple d'étendre l'analyseur de fonction pour tenir compte des tables de saut définies dans le fichier TOML. Comme solution de rechange, le fichier TOML recompiler permet aux utilisateurs de définir manuellement les limites des fonctions.
Exceptions
Le recompilateur ne soutient pas actuellement les exceptions. Ceci est difficile en raison de l'utilisation du registre des liens et du fait que les gestionnaires d'exception peuvent sauter à des emplacements de code arbitraires.
setjmp
setjmpetlongjmpsont mis en œuvre en les redirigeant vers les implémentations natives. Grâce au grand nombre de registres vectoriels de la Xbox 360, la structure d'état du CPU invité est suffisamment grande pour contenir l'état du CPU x86 et potentiellement des états d'autres architectures.
Optimisations
Puisque les binaires Xbox 360 suivent généralement un ABI stable, nous pouvons faire certaines hypothèses sur la structure du code, permettant au compilateur Clang de générer un meilleur code. Plusieurs options d'optimisation sont disponibles dans le recompiler, mais il est recommandé de les tester seulement après une recompilation réussie.
Le registre des liens peut être ignoré en supposant que le jeu n'utilise pas d'exceptions, car tout le processus de recompilation prend déjà en charge le comportement de retour de fonction.
Les registres suivants, en supposant que le jeu ne viole pas l'ABI, peuvent être convertis en variables locales en toute sécurité, car ils ne quittent jamais la portée de la fonction:
- Registre de comptage
- XER
- Registre réservé
- Registres des conditions
- Registres des non-arguments
- Registres non volatils
L'optimisation de la variable locale introduit particulièrement les améliorations, car les appels aux fonctions de restauration/sauvetage du registre peuvent être complètement supprimés, et les magasins redondants à la structure de contexte PPC peuvent être éliminés. DansUnleashed Recompiled, la taille exécutable diminue d'environ 20 Mo avec ces optimisations, et les temps d'image sont réduits de plusieurs millisecondes.
Mécanismes de lots
XenonRecomp définit les fonctions PPC d'une manière qui les rend faciles à crocheter, en utilisant des techniques dans le compilateur Clang. En alias une fonction PPC à une "fonction d'implémentation" et en marquant la fonction originale comme faiblement liée, les utilisateurs peuvent la remplacer par une implémentation personnalisée tout en conservant l'accès à la fonction originale:
PPC_FUNC_IMPL(__imp__sub_XXXXXXXX);
PPC_FUNC(sub_XXXXXXXX)
{
__imp__sub_XXXXXXXX(ctx, base);
}
De plus, les crochets mi-asm peuvent être insérés directement dans le code C++ traduit à des adresses d'instructions spécifiques. Le recompilateur insère ces appels de fonction, et les utilisateurs sont responsables de les mettre en œuvre dans leur projet de recompilation. Le linker les résout lors de la compilation.
Utilisation
Analyse du Xénon
XenonAnalyse, lorsqu'il est utilisé comme application en ligne de commande, permet de passer un fichier XEX comme argument d'entrée pour afficher un fichier TOML contenant toutes les tables de saut détectées dans l'exécutable :
XenonAnalyse [input XEX file path] [output jump table TOML file path]
Cependant, comme expliqué dans les sections précédentes, en raison des variations entre les jeux, un soutien supplémentaire peut être nécessaire pour gérer différents modèles.
An example jump table TOML file can be viewed in the Unleashed Recompiled repository.
XenonRecomp
XenonRecomp accepte un fichier TOML avec des configurations recompiler et le chemin vers leppc_context.hfichier situé dans le répertoire XenonUtils:
XenonRecomp [input TOML file path] [input PPC context header file path]
An example recompiler TOML file can be viewed in the Unleashed Recompiled repository.
Principale
[main]
file_path = "../private/default.xex"
patch_file_path = "../private/default.xexp"
patched_file_path = "../private/default_patched.xex"
out_directory_path = "../ppc"
switch_table_file_path = "SWA_switch_tables.toml"
Tous les chemins sont relatifs au répertoire où le fichier TOML est stocké.
Description des biens - Oui. fichier path=Path vers le fichier XEX. patch file path=Path vers le fichier XEXP. Ceci n'est pas nécessaire si le jeu n'a pas de mise à jour du titre. patched file path=Path dans le fichier XEX patched. XenonRecomp créera automatiquement ce fichier s'il est manquant et le réutilisera dans des recompilations ultérieures. Il ne fait rien si aucun fichier XEXP n'est spécifié. Vous pouvez passer ce fichier de sortie à XenonAnalyse. out directory path=Path vers le répertoire qui contiendra le code de sortie C++. Ce répertoire doit exister avant d'exécuter le recompiler. switch table file path=Path vers le fichier TOML contenant les définitions de la table de saut. Le recompiler utilise ce fichier pour convertir des tables de saut en cas réels de commutation.
Optimisations
skip_lr = false
skip_msr = false
ctr_as_local = false
xer_as_local = false
reserved_as_local = false
cr_as_local = false
non_argument_as_local = false
non_volatile_as_local = false
Active ou désactive diverses optimisations expliquées précédemment dans la documentation. Il est recommandé de ne pas activer ces optimisations jusqu'à ce que vous ayez une recompilation réussie.
Enregistrer Restaurer & Enregistrer les fonctions
restgprlr_14_address = 0x831B0B40
savegprlr_14_address = 0x831B0AF0
restfpr_14_address = 0x831B144C
savefpr_14_address = 0x831B1400
restvmx_14_address = 0x831B36E8
savevmx_14_address = 0x831B3450
restvmx_64_address = 0x831B377C
savevmx_64_address = 0x831B34E4
Les binaires Xbox 360 disposent d'un registre spécialisé qui restaure et enregistre des fonctions qui agissent de la même manière que les cas de basculement. Chaque fonction qui utilise des registres non volatils a une version alignée de ces fonctions ou les appelle explicitement. Le recompilateur nécessite l'adresse de départ de chaque fonction de restauration/enregistrement dans le fichier TOML pour les recompiler correctement. Ces fonctions pourraient probablement être détectées automatiquement, mais il n'y a actuellement aucun mécanisme pour cela.
Description de la propriété
- Oui.
retgprlr 14 adresse Début de l'adresse du__restgprlr_14fonction. Ça commence parld r14, -0x98(r1), répéter la même opération pour le reste des registres non volatils et restaurer le registre de liens à la fine9 c1 ff 68savegprlr 14 adresse Début de l'adresse du__savegprlr_14fonction. Ça commence parstd r14, -0x98(r1), en répétant la même opération pour le reste des registres non volatils et en enregistrant le registre de liens à la finf9 c1 ff 68retfpr 14 adresse Début de l'adresse du__restfpr_14fonction. Ça commence parlfd f14, -0x90(r12), répétant la même opération pour le reste des registres FPU non volatilsc9 cc ff 70savefpr 14 adresse Début de l'adresse du__savefpr_14fonction. Ça commence parstfd r14, -0x90(r12), répétant la même opération pour le reste des registres FPU non volatilsd9 cc ff 70retvmx 14 adresse Début de l'adresse du__restvmx_14fonction. Ça commence parli r11, -0x120etlvx v14, r11, r12, répéter la même opération pour le reste des registres VMX non volatils jusqu'àv31.39 60 fe e0 7d cb 60 cesavevmx 14 adresse Début de l'adresse du__savevmx_14fonction. Ça commence parli r11, -0x120etstvx v14, r11, r12, répéter la même opération pour le reste des registres VMX non volatils jusqu'àv31.39 60 fe e0 7d cb 61 cerestvmx 64 adresse Début de l'adresse du__restvmx_64fonction. Ça commence parli r11, -0x400etlvx128 v64, r11, r12, répétant la même opération pour le reste des registres VMX non volatils39 60 fc 00 10 0b 60 cbsavevmx 64 adresse Début de l'adresse du__savevmx_64fonction. Ça commence parli r11, -0x400etstvx128 v64, r11, r12, répétant la même opération pour le reste des registres VMX non volatils39 60 fc 00 10 0b 61 cb
longjmp & setjmp
longjmp_address = 0x831B6790
setjmp_address = 0x831B6AB0
Ce sont des adresses pour lelongjmpetsetjmpfonctions dans l'exécutable. Le recompiler redirige directement ces fonctions vers des versions natives. La mise en œuvre de ces fonctions peut varier selon les jeux. Dans certains cas, vous pourriez trouverlongjmpen cherchant des appels àRtlUnwindetsetjmptypiquement apparaît juste après.
Si le jeu n'utilise pas ces fonctions, vous pouvez supprimer les propriétés du fichier TOML.
Limites des fonctions explicites
functions = [
{ address = 0x824E7EF0, size = 0x98 },
{ address = 0x824E7F28, size = 0x60 },
]
Vous pouvez définir des limites de fonction explicitement en utilisant lefunctionspropriété si XenonAnalyse ne parvient pas à les analyser correctement, par exemple, avec des fonctions contenant des tables de saut.
Cartes d'instruction non valides
invalid_instructions = [
{ data = 0x00000000, size = 4 }, # Padding
{ data = 0x831B1C90, size = 8 }, # C++ Frame Handler
{ data = 0x8324B3BC, size = 8 }, # C Specific Frame Handler
{ data = 0x831C8B50, size = 8 },
{ data = 0x00485645, size = 44 } # End of .text
]
Dansinvalid_instructionspropriété, vous pouvez définir des valeurs entières 32-bit qui donnent l'instruction au recompilateur de sauter sur certains octets quand il les rencontre. Par exemple, dans Unleashed Recompiled, ils sont utilisés pour sauter les données de traitement d'exception, qui est placé entre les fonctions mais n'est pas valide code.
Crochets mi-asm
[[midasm_hook]]
name = "IndexBufferLengthMidAsmHook"
address = 0x82E26244
registers = ["r3"]
void IndexBufferLengthMidAsmHook(PPCRegister& r3)
{
// ...
}
Vous pouvez définir plusieurs crochets mi-asm dans le fichier TOML, permettant au recompilateur d'insérer des appels de fonction à des adresses spécifiées. Lors de leur mise en œuvre dans votre projet de recompilation, le linker résoudra automatiquement les appels.
Description des biens
- Oui.
Nom de la fonction du crochet mi-asm. Vous pouvez réutiliser les noms de fonctions pour placer la même implémentation à plusieurs adresses. Autrement, les implémentations uniques doivent avoir des noms uniques.
adresse:Adresse de l'instruction où l'appel de la fonction sera placé. Cela n'écrase pas l'instruction à l'adresse spécifiée.
registres Registres pour passer comme arguments au crochet mi-asm. Il s'agit d'une liste de registres car l'optimisation des variables locales ne maintient pas les registres optimisés dans la structure de contexte PPC.
Retour àtruepour indiquer que la fonction où le crochet a été inséré devrait revenir immédiatement après avoir appelé le crochet du milieu-asm.
Retour sur truetruepour indiquer que la fonction doit revenir si l'appel au crochet de mi-asm retournetrue.
Return on falsetruepour indiquer que la fonction doit revenir si l'appel au crochet de mi-asm retournefalse.
Adresse de saut L'adresse à sauter immédiatement après avoir appelé l'hameçon. L'adresse doit être dans la même fonction où le crochet a été placé.
jump address on true L'adresse à laquelle sauter si le crochet mi-asm revienttrue. L'adresse doit être dans la même fonction où le crochet a été placé.
jump address on false L'adresse à laquelle sauter si le crochet mi-asm revientfalse. L'adresse doit être dans la même fonction où le crochet a été placé.
après l'instructiontrueplacer le crochet mi-asm immédiatement après l'instruction, au lieu d'avant.
Certaines propriétés sont mutuellement exclusives. Par exemple, vous ne pouvez pas utiliser les deuxreturnetjump_address, et les retours/jumps directs ou conditionnels ne peuvent être mélangés. Le recompilateur va afficher des avertissements si cela n'est pas suivi.
Essais
XenonRecomp peut recompiler les tests PPC de Xenia et les exécuter via le projet XenonTests dans le dépôt. Après avoir construit les tests en utilisant le système de construction de Xenia, XenonRecomp peut traiter lasrc/xenia/cpu/ppc/testing/binrépertoire comme entrée, générant des fichiers C++ dans le répertoire de sortie spécifié:
XenonRecomp [input testing directory path] [input PPC context header file path] [output directory path]
Une fois les fichiers générés, rafraîchir le cache de XenonTests pour les faire apparaître dans le projet. Les tests peuvent ensuite être exécutés pour comparer les résultats des instructions aux valeurs attendues.
Bâtiment
Le projet nécessite CMake 3.20 ou plus tard et Clang 18 ou plus tard à construire. Puisque le dépôt comprend des sous-modules, assurez-vous de le cloner récursivement.
Les compilateurs autres que Clang n'ont pas été testés et ne sont pas recommandés, y compris pour la récupération. Le projet repose sur des intrinsèques et des techniques spécifiques au compilateur qui peuvent ne pas fonctionner correctement sur d'autres compilateurs, et de nombreuses méthodes d'optimisation dépendent de la génération de code de Clang.
Sous Windows, vous pouvez utiliser le jeu d'outils clang-cl et ouvrir le projet dans l'intégration CMake de Visual Studio.
Spécial Je vous remercie
Ce projet n'aurait pu être possible sansXeniaémulateur, comme beaucoup de parties du processus de conversion de code CPU a été mis en œuvre en référant fortement son traducteur de code PPC. Le projet utilise également le code deXenia Canarypour corriger les binaires XEX.