Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click Here!
Click Here!
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


Chapter 5
Java Byte Code

The last chapter walked you through the disassembly of a Java .class file. However, I left one crucial part of the file — the bodies of the different methods — in raw bytes rather than converting it back to .java source code. This large topic easily deserves a chapter of its own.

Method bodies are one of the few areas in which it is not always possible to return to the source code format. For one thing, you completely lose all of the information about the identifiers inside a method or in a method’s argument list in the compilation phase. There’s no way to get it back. Furthermore, .java source code keywords like for and while don’t always map in a one-to-one fashion onto the byte code equivalents. For example, for every for loop, there’s an equivalent while loop that produces the same byte code. Given only the byte code, there’s no way to tell which one was in the source code. Finally, optimizing compilers essentially rewrite .java source code before turning it into byte code. When you reverse the process, you get back the rewritten source code, not the original.

Although fully accurate decompilation is, in general, not possible, with practice you can learn to understand what the byte codes say. The fundamental problem is that there’s often more than one way to say the same thing. However, if you care only about the meaning of what was said, rather than the exact way in which it was expressed, you can extract the meaning from the byte codes. You learn to do this in this chapter.


Note:  If debugging information is included in the file, then the .class file has a complete copy of the source code, and you can get everything back. However, that is a relatively unchallenging and uninteresting case, so this chapter covers the harder case in which no debugging information is included in the file.

Byte Code Mnemonics

The code in a method body is a linear sequence of bytes. Each byte has an unsigned value between zero and 255. The interpretation of each byte depends on its position. The zeroth byte is always a .java byte code instruction (an opcode, for short). Bytes after that point can be either byte code instructions or arguments for byte code instructions. For example, if the byte at position zero in a method is 16, then the byte at position one is not a byte code, but rather a signed byte to be pushed onto the stack. Data values embedded directly in the code like this are sometimes called literals.

The only way to distinguish between opcodes and literals is by starting with the instruction at position zero in the code array and working forward. For example, if the byte zero is 16 and opcode 16 is known to take a one-byte argument, then byte one must be the literal argument for the instruction and byte two must be the next opcode.

Most instructions have a precisely defined number of bytes that should be read as literals following the opcode itself. Opcode 16 always takes exactly one byte as an argument, never zero bytes and never more than one byte. Arguments that by their nature do not take up a fixed number of bytes, such as arrays and strings, are not directly included in the code array. Instead, a 2-byte index into the constant pool is given. Therefore, once you know the possible byte codes and their arguments, you can distinguish between instructions and data. Java enforces the dichotomy between code and data very strictly. This is an essential feature of Java’s security.

Human beings aren’t very good at remembering the meanings of many small numbers like the 200-plus opcodes. Sun has therefore defined mnemonic strings for these codes. These strings are listed in Table 5-1.

Table 5-1 .java byte codes

Byte Code Mnemonic Number of Bytes in the Argument Meaning

0 nop 0 Do nothing (no operation); skip to the next instruction.
1 aconst_null 0 Push null onto the stack.
2 iconst_m1 0 Push the int -1 onto the stack.
3 iconst_0 0 Push the int 0 onto the stack.
4 iconst_1 0 Push the int 1 onto the stack.
5 iconst_2 0 Push the int 2 onto the stack.
6 iconst_3 0 Push the int 3 onto the stack.
7 iconst_4 0 Push the int 4 onto the stack.
8 iconst_5 0 Push the int 5 onto the stack.
9 lconst_0 0 Push the long 0 onto the stack.
10 lconst_1 0 Push the long 1 onto the stack.
11 fconst_0 0 Push the float 0.0 onto the stack.
12 fconst_1 0 Push the float 1.0 onto the stack.
13 fconst_2 0 Push the float 2.0 onto the stack.
14 dconst_0 0 Push the double 0.0 onto the stack.
15 dconst_1 0 Push the double 1.0 onto the stack.
16 bipush 1 Sign-extend the byte to an int, and push it onto the stack.
17 sipush 2 Combine the bytes into a short, sign-extend it to an int, and push it onto the stack.
18 ldc 1 Push the integer, float, or string at the specified index in the constant pool onto the stack.
19 ldc_w 2 Push the integer, float, or string at the specified index in the constant pool onto the stack.
20 ldc2_w 2 Push the long or double at the specified index in the constant pool onto the stack.
21 iload 1 Push the int local variable at the specified index onto the stack.
22 lload 1 Push the long local variable at the specified index onto the stack.
23 fload 1 Push the float local variable at the specified index onto the stack.
24 dload 1 Push the double local variable at the specified index onto the stack.
25 aload 1 Push the reference at the specified index onto the stack.
26 iload_0 0 Push the int variable at the zeroth position in the local frame onto the stack.
27 iload_1 0 Push the int variable at the first position in the local frame onto the stack.
28 iload_2 0 Push the int variable at the second position in the local frame onto the stack.
29 iload_3 0 Push the int variable at the third position in the local frame onto the stack.
30 lload_0 0 Push the long variable at the zeroth position in the local frame onto the stack.
31 lload_1 0 Push the long variable at the first position in the local frame onto the stack.
32 lload_2 0 Push the long variable at the second position in the local frame onto the stack.
33 lload_3 0 Push the long variable at the third position in the local frame onto the stack.
34 fload_0 0 Push the float variable at the zeroth position in the local frame onto the stack.
35 fload_1 0 Push the float variable at the first position in the local frame onto the stack.
36 fload_2 0 Push the float variable at the second position in the local frame onto the stack.
37 fload_3 0 Push the float variable at the third position in the local frame onto the stack.
38 dload_0 0 Push the double variable at the zeroth position in the local frame onto the stack.
39 dload_1 0 Push the double variable at the first position in the local frame onto the stack.
40 dload_2 0 Push the double variable at the second position in the local frame onto the stack.
41 dload_3 0 Push the double variable at the third position in the local frame onto the stack.
42 aload_0 0 Push the reference variable at the zeroth position in the local frame onto the stack.
43 aload_1 0 Push the reference variable at the first position in the local frame onto the stack.
44 aload_2 0 Push the reference variable at the second position in the local frame onto the stack.
45 aload_3 0 Push the reference variable at the third position in the local frame onto the stack.
46 iaload 0 Push an int from an array onto the stack.
47 laload 0 Push a long from an array onto the stack.
48 faload 0 Push a float from an array onto the stack.
49 daload 0 Push a double from an array onto the stack.
50 aaload 0 Push a reference from an array onto the stack.
51 baload 0 Push a byte or Boolean from an array onto the stack.
52 caload 0 Push a char from an array onto the stack.
53 saload 0 Push a short from an array onto the stack.
54 istore 1 Store an int into the local variable at the specified index.
55 lstore 1 Store a long into the local variable at the specified index.
56 fstore 1 Store a float into the local variable at the specified index.
57 dstore 1 Store a double into the local variable at the specified index.
58 astore 1 Store a reference into the local variable at the specified index.
59 istore_0 0 Pop an int value from the stack, and store it in the local variable at index 0.
60 istore_1 0 Pop an int value from the stack, and store it in the local variable at index 1.
61 istore_2 0 Pop an int value from the stack, and store it in the local variable at index 2.
62 istore_3 0 Pop an int value from the stack, and store it in the local variable at index 3.
63 lstore_0 0 Pop a long value from the stack, and store it in the local variable at index 0.
64 lstore_1 0 Pop a long value from the stack, and store it in the local variable at index 1.
65 lstore_2 0 Pop a long value from the stack, and store it in the local variable at index 2.
66 lstore_3 0 Pop a long value from the stack, and store it in the local variable at index 3.
67 fstore_0 0 Pop a float value from the stack, and store it in the local variable at index 0.
68 fstore_1 0 Pop a float value from the stack, and store it in the local variable at index 1.
69 fstore_2 0 Pop a float value from the stack, and store it in the local variable at index 2.
70 fstore_3 0 Pop a float value from the stack, and store it in the local variable at index 3.
71 dstore_0 0 Pop a double value from the stack, and store it in the local variable at index 0.
72 dstore_1 0 Pop a double value from the stack, and store it in the local variable at index 1.
73 dstore_2 0 Pop a double value from the stack, and store it in the local variable at index 2.
74 dstore_3 0 Pop a double value from the stack, and store it in the local variable at index 3.
75 astore_0 0 Pop a reference value from the stack, and store it in the local variable at index 0.
76 astore_1 0 Pop a reference value from the stack, and store it in the local variable at index 1.
77 astore_2 0 Pop a reference value from the stack, and store it in the local variable at index 2.
78 astore_3 0 Pop a reference value from the stack, and store it in the local variable at index 3.
79 iastore 0 Store a value from the stack into an int array.
80 lastore 0 Store a value from the stack into a long array.
81 fastore 0 Store a value from the stack into a float array.
82 dastore 0 Store a value from the stack into a double array.
83 aastore 0 Store a value from the stack into a reference array.
84 bastore 0 Store a value from the stack into a byte or Boolean array.
85 castore 0 Store a value from the stack into a char array.
86 sastore 0 Store a value from the stack into a short array.
87 pop 0 Pop a word from the stack, and throw it away.
88 pop2 0 Pop two words from the stack, and throw them away.
89 dup 0 Duplicate the top word of the stack onto the top of the stack.
90 dup_x1 0 Duplicate the top word of the stack, and put it two down in the stack.
91 dup_x2 0 Duplicate the top word of the stack, and put it three down in the stack.
92 dup2 0 Duplicate the top two words on the stack onto the top of the stack.
93 dup2_x1 0 Duplicate the top two words of the stack, and put them three down in the stack.
94 dup2_x2 0 Duplicate the top two words of the stack, and put them four down in the stack.
95 swap Swap the top two words on the stack.
96 iadd 0 Add two ints.
97 ladd 0 Add two longs.
98 fadd 0 Add two floats.
99 dadd 0 Add two doubles.
100 isub 0 Subtract two ints.
101 lsub 0 Subtract two longs.
102 fsub 0 Subtract two floats.
103 dsub 0 Subtract two doubles.
104 imul 0 Multiply two ints.
105 lmul 0 Multiply two longs.
106 fmul 0 Multiply two floats.
107 dmul 0 Multiply two doubles.
108 idiv 0 Divide two ints.
109 ldiv 0 Divide two longs.
110 fdiv 0 Divide two floats.
111 ddiv 0 Divide two doubles.
112 irem 0 Take the remainder of two ints.
113 lrem 0 Take the remainder of two longs.
114 frem 0 Take the remainder of two floats.
115 drem 0 Take the remainder of two doubles.
116 ineg 0 Change the sign of the int on the top of the stack.
117 lneg 0 Change the sign of the long on the top of the stack.
118 fneg 0 Change the sign of the float on the top of the stack.
119 dneg 0 Change the sign of the double on the top of the stack.
120 ishl 0 Shift an int left.
121 lshl 0 Shift a long left.
122 ishr 0 Shift an int right with sign extension.
123 lshr 0 Shift a long right with sign extension.
124 iushr 0 Shift an int right without sign extension.
125 lushr 0 Shift a long right without sign extension.
126 iand 0 Bitwise and of the two ints on the top of the stack.
127 land 0 Bitwise and of the two longs on the top of the stack.
128 ior 0 Bitwise or of the two ints on the top of the stack.
129 lor 0 Bitwise or of the two longs on the top of the stack.
130 ixor 0 Bitwise exclusive-or of the two ints on the top of the stack.
131 lxor 0 Bitwise exclusive-or of the two longs on the top of the stack.
132 iinc 2 Increment the local variable at the first argument by the signed byte at the second argument.
133 i2l 0 Convert int to long.
134 i2f 0 Convert int to float.
135 i2d 0 Convert int to double.
136 l2i 0 Convert long to int.
137 l2f 0 Convert long to float.
138 l2d 0 Convert long to double.
139 f2i 0 Convert float to int.
140 f2l 0 Convert float to long.
141 f2d 0 Convert float to double.
142 d2i 0 Convert double to int.
143 d2l 0 Convert double to long.
144 d2f 0 Convert double to float.
145 i2b 0 Convert int to byte.
146 i2c 0 Convert int to char.
147 i2s 0 Convert int to short.
148 lcmp 0 Compare two longs.
149 fcmpl 0 Compare two floats.
150 fcmpg 0 Compare two floats.
151 dcmpl 0 Compare two doubles.
152 dcmpg 0 Compare two doubles.
153 ifeq 2 Branch if the int on the top of the stack is equal to zero.
154 ifne 2 Branch if the int on the top of the stack is not equal to zero.
155 iflt 2 Branch if the int on the top of the stack is less than zero.
156 ifge 2 Branch if the int on the top of the stack is greater than or equal to zero.
157 ifgt 2 Branch if the int on the top of the stack is greater than zero.
158 ifle 2 Branch if the int on the top of the stack is less than or equal to zero.
159 if_icmpeq 2 Branch if the two ints on the top of the stack are equal.
160 if_icmpne 2 Branch if the two ints on the top of the stack are not equal.
161 if_icmplt 2 Branch if the int second from the top of the stack is less than the int on the top of the stack.
162 if_icmpge 2 Branch if the int second from the top of the stack is greater than or equal to the int on the top of the stack.
163 if_icmpgt 2 Branch if the int second from the top of the stack is greater than the int on the top of the stack.
164 if_icmple 2 Branch if the int second from the top of the stack is less than or equal to the int on the top of the stack.
165 if_acmpeq 2 Branch to the address specified in the argument if the two references on the top of the stack are equal.
166 if_acmpne 2 Branch to the address specified in the argument if the two references on the top of the stack are not equal.
167 goto 2 Go to address specified in the arguments.
168 jsr 2 Jump to a subroutine.
169 ret 1 Return from a subroutine.
170 tableswitch variable Compare value and branch.
171 lookupswitch variable Compare value and branch.
172 ireturn 0 Return an int from a method.
173 lreturn 0 Return a long from a method.
174 freturn 0 Return a float from a method.
175 dreturn 0 Return a double from a method.
176 areturn 0 Return a reference from a method.
177 return 0 Return void from method.
178 getstatic 2 Get a static field from a class.
179 putstatic 2 Sets a static field in a class.
180 getfield 2 Get a field from an object.
181 putfield 2 Set a field in an object.
182 invokevirtual 2 Call an instance method.
183 invokespecial 2 Call a constructor in special circumstances.
184 invokestatic 2 Call a static method.
185 invokeinterface 4 Call an interface method.
186 Not used in Java 1.0.2.
187 new 2 Create a new object.
188 newarray 1 Create a new array of primitive types.
189 anewarray 2 Create a new array of references.
190 arraylength 0 Get the length of an array.
191 athrow 0 Throw exception or error.
192 checkcast 2 Check casts between object types.
193 instanceof 2 Determine if an object has a given type.
194 monitorenter 0 Allow a thread to take ownership of the monitor associated with an object.
195 monitorexit 0 Allow a thread to give up ownership of the monitor associated with an object.
196 wide 4 or 6 Extend the local variable index used by the iload, aload, fload, dload, istore, astore, fstore, dstore, ret, and iinc instructions.
197 multianewarray 3 Create a new multidimensional array.
198 ifnull 2 Branch to the address specified in the arguments if the reference popped from the top of the stack is null.
199 ifnonnull 2 Branch to the address specified in the arguments if the reference popped from the top of the stack is not null.
200 goto_w 4 Branch to the address specified in the arguments.
201 jsr_w 4 Jump to the subroutine at the address specified in the arguments.

Although these mnemonics may seem just as cryptic as the raw bytes at first glance, they do have a logic to them. For example, opcodes that begin with the letter i commonly operate on int types. Instructions that begin with the letter l operate on longs. Instructions that begin with f operate on floats, and instructions that begin with d operate on doubles. Instructions that begin with a operate on references. Opcodes that contain the word add generally add things. Opcodes that contain the word sub generally subtract things. You get the idea. The rest of this chapter looks at what these instructions do. By the time you finish this chapter, these mnemonics will make perfect sense to you.


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.