Vous vous lancez dans un voyage à travers le monde du Bytecode Java ? Cet article couvre tout ce que vous devez savoir pour commencer.
En 1995, Sun Microsystems, les créateurs de la programmation Java langue, a fait une affirmation audacieuse. Ils ont dit que Java vous permettrait « d’écrire une fois et de l’exécuter n’importe où ». Cela signifiait que les binaires compilés seraient capables de s'exécuter sur n'importe quelle architecture système, ce que C ne pouvait pas faire et qui reste à ce jour un élément essentiel de l'écriture de Java.
Pour obtenir cette capacité multiplateforme, Java utilise une approche unique lors de la compilation. Au lieu de passer directement du code source au code machine (qui serait spécifique à chaque architecture système), Java compile ses programmes sous une forme intermédiaire appelée bytecode. Le bytecode est un ensemble d'instructions qui n'est ni lié à un langage machine particulier ni dépendant d'une architecture matérielle spécifique. Cette abstraction est la clé de la portabilité de Java.
Le programme qui interprète et exécute les instructions du bytecode Java est appelé machine virtuelle Java (JVM). La JVM traduit chaque instruction de bytecode en code machine natif de l'architecture système particulière sur laquelle elle s'exécute. Ce processus, souvent appelé compilation « juste à temps » (JIT), permet d'exécuter le bytecode Java aussi efficacement que possible sur n'importe quelle plate-forme donnée.
Le bytecode n'est pas Mais ce n'est pas seulement utile pour la JVM. Étant donné que le bytecode d'une classe Java est utile pour l'ingénierie inverse, l'optimisation des performances, la recherche de sécurité et d'autres fonctions d'analyse statique, le JDK est livré avec des utilitaires pour nous aider, vous et moi, à l'inspecter.
Pour avoir un aperçu d'un exemple de bytecode, considérons les deux méthodes suivantes de `java.lang.Boolean`, `booleanValue` et `valueOf(boolean)` qui respectivement déballer et encadrer le type primitif `boolean` :
public boolean booleanValue() { return value; } public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
Utilisation du ` javap`, fournie avec le JDK, nous pouvons voir le bytecode de chacun. Vous pouvez le faire en exécutant `javap` avec la commande `-c` et le nom complet de la classe, comme ceci :
javap -c java.lang.Boolean
Le résultat est le bytecode de toutes les méthodes publiques dans ` java.lang.Boolean`. Ici, j'ai copié uniquement le bytecode de `booleanValue` et `valueOf(boolean)` :
public boolean booleanValue(); code: 0: aload_0 1: getfield #7 // Field value:Z 4: ireturn public static java.lang.Boolean valueOf(boolean); Code: 0: iload_0 1: ifeq 10 4: getstatic #27 // Field TRUE:Ljava/lang/Boolean; 7: goto 13 10: getstatic #31 // Field FALSE:Ljava/lang/Boolean; 13: areturn
À première vue, c'est un tout nouveau langage à apprendre. Cependant, cela devient rapidement simple lorsque vous apprenez ce que fait chaque instruction et que Java fonctionne avec une pile.
Prenons par exemple les trois instructions de bytecode pour `booleanValue` :
`aload_n` signifie placer une référence à une variable locale sur la pile. Dans une instance de classe, `aload_0` fait référence à `this`.
`getfield` signifie lire la variable membre à partir de `this` (l'élément inférieur de la pile) et la placer valeur sur la pile
`#7` fait référence à l'index de la référence dans le pool constant
`// Valeur du champ : Z` indique nous à quoi `#7` fait référence, un champ nommé `value` de type `boolean` (Z)
`ireturn` signifie afficher une valeur primitive hors de la pile et le renvoyer
Pour faire court, ces trois instructions recherchent le champ `value` de l'instance et le renvoient.
Comme deuxième exemple, prenons un regardez la méthode suivante, `valueOf(boolean)` :
`iload_n` signifie placer une variable locale primitive sur la pile. `iload_0` fait référence au premier paramètre de méthode (puisque le premier paramètre de méthode est une primitive)
`ifeq n` signifie retirer la valeur de la pile et voir si elle est vraie ; si c'est le cas, passez à la ligne suivante, sinon passez à la ligne `n`
`getstatic #n` signifie lire un membre statique sur la pile
`#27` fait référence à l'index du membre statique dans le pool de constantes
`// Field TRUE:Ljava/lang/Boolean` nous dit à quoi `#27` fait référence , un membre statique nommé `TRUE` de type `Boolean
`goto n` signifie maintenant passer à la ligne `n` dans le bytecode
`areturn` signifie extraire une référence de la pile et la renvoyer
En d'autres termes, ces instructions disent de prendre le premier paramètre de méthode, si c'est vrai , puis retournez `Boolean.TRUE` ; sinon, renvoyez `Boolean.FALSE`.
J'ai mentionné plus tôt que cela peut être utile pour l'ingénierie inverse, l'optimisation des performances et la recherche sur la sécurité. Développons-les maintenant.
Lorsque vous travaillez avec des bibliothèques tierces ou des composants à source fermée, l'analyse du bytecode devient un outil puissant. La décompilation du bytecode peut donner un aperçu du fonctionnement interne de ces bibliothèques, facilitant l'intégration, le dépannage et garantissant la compatibilité.
Dans les situations où vous rencontrez du code Java propriétaire ou à source fermée, la lecture du bytecode peut être la seule solution possible. manière de comprendre sa fonctionnalité. L'analyse du bytecode vous permet de faire de l'ingénierie inverse et de comprendre le comportement des applications fermées, facilitant ainsi l'interopérabilité ou la personnalisation.
À titre d'exemple concret, j'essayais récemment d'intégrer un outil d'analyse d'enchevêtrement de packages tiers dans notre système Ci. Malheureusement, le fournisseur était de source fermée et ne disposait que d'une documentation expliquant comment accéder à la bibliothèque via son interface utilisateur propriétaire. En analysant le bytecode, j'ai pu procéder à l'ingénierie inverse des entrées et sorties attendues du moteur d'analyse sous-jacent.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!