The Java binary instruction code is in a compact arrangement in the following format (opcode occupies one byte ):
Opcode operand *
Except for the tableswitch and lookupswitch commands, there are no padding bytes in other commands, even between the two commands. Therefore, when reading a command, you must read it according to the definition of the command.
Through the analysis of the preceding Java instruction set, we can know that a large part of the Java Instruction Set has no operands. Therefore, for this part of the instruction set, we only need to read the operational code of one byte, you can map the operation code to a mnemonic.
For other commands with operands, You need to analyze the bytecode based on different types (because of the support of bcel (Binary Code Engineering Library) in apache, The ing between the operation Code and the mnemonic can be done using com.sun.org. apache. bcel. internal. in Constats ).
1. process two special commands: tableswitch and lookupswitch.
For both commands, you must first remove the padding characters so that the defaultbyte1 index number is word-aligned.
Private static void make4ByteAlignment (ByteSequence codes ){
Int usedBytes = codes. getIndex () % 4;
Int paddingBytes = (usedBytes = 0 )? 0: 4-usedBytes;
For (int I = 0; I <paddingBytes; I ++ ){
Codes. readByte ();
}
}
For the tableswitch command, read the defaultoffset value, the minimum item value, the limit item value, and the offset value of each item between the minimum item and the limit item. Add the read offset value to the base address of the current command:
Int defaultOffset1 = baseOffset + codes. readInt ();
Builder. append ("\ tdefault = #" + defaultOffset1 );
Int low = codes. readInt ();
Int high = codes. readInt ();
Int npair1 = high-low + 1;
Builder. append (", npairs =" + npair1 + "\ n ");
For (int I = low; I <= high; I ++ ){
Int match = I;
Offset = baseOffset + codes. readInt ();
Builder. append (String. format ("\ tcase % d: # % d \ n", match, offset ));
}
For the lookupswitch command, read the defaultoffset value, key-Value Pair value (npairs), and npairs key-value pair, and add the obtained offset value to the base address of the current command:
Int defaultOffset2 = baseOffset + codes. readInt ();
Builder. append ("\ tdefault = #" + defaultOffset2 );
Int npairs2 = codes. readInt ();
Builder. append (", npairs =" + npairs2 + "\ n ");
For (int I = 0; I <npairs2; I ++ ){
Int match = codes. readInt ();
Offset = baseOffset + codes. readInt ();
Builder. append (String. format ("\ tcase % d: # % d \ n", match, offset ));
}
2. All conditional jump commands have two-byte offset operands (if <cond>, if_icmp <cond>, ifnull, ifnonnull, if_acmp <cond> ). Both the unconditional jump instruction goto and the subroutine jump instruction jsr are two-byte offsets as the operands.
Offset = baseOffset + codes. readShort ();
Builder. append (String. format ("\ t # % d \ n", offset ));
3. The operands of the jump instruction goto_w and the Child-routine jump instruction jsr_w are the four-byte offsets.
Offset = baseOffset + codes. readInt ();
Builder. append (String. format ("\ t # % d \ n", offset ));
4. The wide command continues reading the next command and sets the wide parameter to true.
ByteCodeToString (codes, pool, verbose, true );
5. Some directive values use the local variable index number of one byte as the operand. If wide is used for modification, two bytes are used as the operand to represent the local variable index number. Such Commands include aload, iload, fload, lload, dload, astore, istore, fstore, lstore, dstore, and ret.
If (wide ){
Index = codes. readUnsignedShort ();
} Else {
Index = codes. readUnsignedByte ();
}
Builder. append (String. format ("\ t % d \ n", index ));
6. the iinc command takes a local variable index number of one byte and a constant of its own as the parameter. If it is modified with wide, the local variable index number and constant of this command both occupy two bytes.
If (wide ){
Index = codes. readUnsignedShort ();
ConstValue = codes. readShort ();
} Else {
Index = codes. readUnsignedByte ();
ConstValue = codes. readByte ();
}
Builder. append (String. format ("\ t % d \ n", index, constValue ));
7. Object operation commands. Their operands are indexes in the constant pool and the length is two bytes. Point to the CONSTANT_Class_info type structure. These Commands include new, checkcast, instanceof, and anewarray.
Index = codes. readUnsignedShort ();
Builder. append ("\ t" + pool. getClassInfo (index). toInstructionString (verbose) + "\ n ");
8. All field operation commands. Their operands are indexes in the constant pool and the length is two bytes. Point to the CONSTANT_Fieldref_info type structure. These Commands include getfield, putfield, getstatic, and putstatic.
Index = codes. readUnsignedShort ();
Builder. append ("\ t" + pool. getFieldRefInfo (index). toInstructionString (verbose) + "\ n ");
9. Non-interface method call commands also use two-byte index numbers as the operands and point to the CONSTANT_Methodref_info type structure in the constant pool. These Commands include invokespecial, invokevirtual, and invokestatic.
Index = codes. readUnsignedShort ();
Builder. append ("\ t" + pool. getMethodRefInfo (index). toInstructionString (verbose) + "\ n ");
10. interface method call command invokeinterface, which has four-byte operands. The first two bytes are the index number of the constant pool and point to the CONSTANT_InterfaceMethodref_info type. The third byte is count, indicating the number of bytes of the parameter, the last byte is 0.
Index = codes. readUnsignedShort ();
Int nargs = codes. readUnsignedByte (); // Historical, redundant
Builder. append ("\ t" + pool. getInterfaceMethodRefInfo (index). toInstructionString (verbose ));
Builder. append (":" + nargs + "\ n ");
Codes. readUnsignedByte (); // reserved shocould be zero
11. The basic type of the array creation command newarray. Its operand is a byte type identifier.
String type = Constants. TYPE_NAMES [codes. readByte ()];
Builder. append (String. format ("\ t (% s) \ n", type ));
12. the multi-dimensional array creation command multianewarray has three-byte operands. The first two bytes are the index numbers and point to the CONSTANT_Class_info type, indicating the array type. The last byte specifies the array dimension.
Index = codes. readUnsignedShort ();
Int dimensions = codes. readUnsignedByte ();
Builder. append (String. format ("\ t % s (% d) \ n", pool. getClassInfo (index). getName (), dimensions ));
13. the constant stack entry command ldc uses a byte index number as a parameter and points to the CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_String_info, and CONSTANT_Class_info types, the constant value (int type value, float type value, String reference type value, or object reference type value) to be imported into the stack ).
Index = codes. readUnsignedByte ();
Builder. append ("\ t" + pool. getPoolItem (index). toInstructionString (verbose) + "\ n ");
14. ldc_w, a constant of wide index, uses two-byte index numbers as parameters and points to the CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_String_info, and CONSTANT_Class_info types, the constant value (int type value, float type value, String reference type value, or object reference type value) to be imported into the stack ).
Index = codes. readUnsignedShort ();
Builder. append ("\ t" + pool. getPoolItem (index). toInstructionString (verbose) + "\ n ");
15. ldc2_w, a constant entry stack instruction for wide indexes, uses two-byte index numbers as parameters and points to the CONSTANT_Long_info and CONSTANT_Double_info types, the constant value (long and double) to be imported into the stack ).
Index = codes. readUnsignedShort ();
Builder. append ("\ t" + pool. getPoolItem (index). toInstructionString (verbose) + "\ n ");
16. The bipush command uses a byte constant as the operand.
Byte constByte = codes. readByte ();
Builder. append ("\ t" + constByte );
17. The sipush command uses two-byte constants as the operands.
Short constShort = codes. readShort ();
Builder. append ("\ t" + constShort );
There are still some unfinished code, including the signature and descriptor of the field (method) Not parsed, and some parsing formats need to be adjusted. In any case, the overall structure is like this, and the others are details. We will not discuss them here.
Author: "Good at water"