1. 程式人生 > >深入理解JVM-java字節碼文件結構剖析(練習解讀字節碼)

深入理解JVM-java字節碼文件結構剖析(練習解讀字節碼)

const class store bytes ret inf get 構造器 art

public class MyTest2 {
    String str = "Welcome";
    private int x = 5;
    public static Integer in = 10;
    public static void main(String[] args) {
        MyTest2 myTest2 = new MyTest2();
        myTest2.setX(8);
        in  =20;
    }

    public void setX(int x) {
        this.x = x;
    }
}

javap -verbose jvm.bytecode.MyTest2

Classfile /Users/luozhiyun/Documents/work/jvm_lecture/target/classes/jvm/bytecode/MyTest2.class
  Last modified Mar 16, 2019; size 823 bytes
  MD5 checksum 2e0c9064f75aa1f5a5057f17e228387f
  Compiled from "MyTest2.java"
public class jvm.bytecode.MyTest2
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#34        // java/lang/Object."<init>":()V
   #2 = String             #35            // Welcome
   #3 = Fieldref           #5.#36         // jvm/bytecode/MyTest2.str:Ljava/lang/String;
   #4 = Fieldref           #5.#37         // jvm/bytecode/MyTest2.x:I
   #5 = Class              #38            // jvm/bytecode/MyTest2
   #6 = Methodref          #5.#34         // jvm/bytecode/MyTest2."<init>":()V
   #7 = Methodref          #5.#39         // jvm/bytecode/MyTest2.setX:(I)V
   #8 = Methodref          #40.#41        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #9 = Fieldref           #5.#42         // jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
  #10 = Class              #43            // java/lang/Object
  #11 = Utf8               str
  #12 = Utf8               Ljava/lang/String;
  #13 = Utf8               x
  #14 = Utf8               I
  #15 = Utf8               in
  #16 = Utf8               Ljava/lang/Integer;
  #17 = Utf8               <init>
  #18 = Utf8               ()V
  #19 = Utf8               Code
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               Ljvm/bytecode/MyTest2;
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               args
  #27 = Utf8               [Ljava/lang/String;
  #28 = Utf8               myTest2
  #29 = Utf8               setX
  #30 = Utf8               (I)V
  #31 = Utf8               <clinit>
  #32 = Utf8               SourceFile
  #33 = Utf8               MyTest2.java
  #34 = NameAndType        #17:#18        // "<init>":()V
  #35 = Utf8               Welcome
  #36 = NameAndType        #11:#12        // str:Ljava/lang/String;
  #37 = NameAndType        #13:#14        // x:I
  #38 = Utf8               jvm/bytecode/MyTest2
  #39 = NameAndType        #29:#30        // setX:(I)V
  #40 = Class              #44            // java/lang/Integer
  #41 = NameAndType        #45:#46        // valueOf:(I)Ljava/lang/Integer;
  #42 = NameAndType        #15:#16        // in:Ljava/lang/Integer;
  #43 = Utf8               java/lang/Object
  #44 = Utf8               java/lang/Integer
  #45 = Utf8               valueOf
  #46 = Utf8               (I)Ljava/lang/Integer;
{
  java.lang.String str;
    descriptor: Ljava/lang/String;
    flags:

  public static java.lang.Integer in;
    descriptor: Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_STATIC

  public jvm.bytecode.MyTest2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: ldc           #2                  // String Welcome
         7: putfield      #3                  // Field str:Ljava/lang/String;
        10: aload_0
        11: iconst_5
        12: putfield      #4                  // Field x:I
        15: return
      LineNumberTable:
        line 6: 0
        line 7: 4
        line 8: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  this   Ljvm/bytecode/MyTest2;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #5                  // class jvm/bytecode/MyTest2
         3: dup
         4: invokespecial #6                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: bipush        8
        11: invokevirtual #7                  // Method setX:(I)V
        14: bipush        20
        16: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        19: putstatic     #9                  // Field in:Ljava/lang/Integer;
        22: return
      LineNumberTable:
        line 11: 0
        line 12: 8
        line 13: 14
        line 14: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0  args   [Ljava/lang/String;
            8      15     1 myTest2   Ljvm/bytecode/MyTest2;

  public void setX(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field x:I
         5: return
      LineNumberTable:
        line 17: 0
        line 18: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Ljvm/bytecode/MyTest2;
            0       6     1     x   I

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        10
         2: invokestatic  #8                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         5: putstatic     #9                  // Field in:Ljava/lang/Integer;
         8: return
      LineNumberTable:
        line 9: 0
}
SourceFile: "MyTest2.java"

字節碼

cafe babe 0000 0034 002f 0a00 0a00 2208
0023 0900 0500 2409 0005 0025 0700 260a
0005 0022 0a00 0500 270a 0028 0029 0900
0500 2a07 002b 0100 0373 7472 0100 124c
6a61 7661 2f6c 616e 672f 5374 7269 6e67
3b01 0001 7801 0001 4901 0002 696e 0100
134c 6a61 7661 2f6c 616e 672f 496e 7465
6765 723b 0100 063c 696e 6974 3e01 0003
2829 5601 0004 436f 6465 0100 0f4c 696e
654e 756d 6265 7254 6162 6c65 0100 124c
6f63 616c 5661 7269 6162 6c65 5461 626c
6501 0004 7468 6973 0100 164c 6a76 6d2f
6279 7465 636f 6465 2f4d 7954 6573 7432
3b01 0004 6d61 696e 0100 1628 5b4c 6a61
7661 2f6c 616e 672f 5374 7269 6e67 3b29
5601 0004 6172 6773 0100 135b 4c6a 6176
612f 6c61 6e67 2f53 7472 696e 673b 0100
076d 7954 6573 7432 0100 0473 6574 5801
0004 2849 2956 0100 083c 636c 696e 6974
3e01 000a 536f 7572 6365 4669 6c65 0100
0c4d 7954 6573 7432 2e6a 6176 610c 0011
0012 0100 0757 656c 636f 6d65 0c00 0b00
0c0c 000d 000e 0100 146a 766d 2f62 7974
6563 6f64 652f 4d79 5465 7374 320c 001d
001e 0700 2c0c 002d 002e 0c00 0f00 1001
0010 6a61 7661 2f6c 616e 672f 4f62 6a65
6374 0100 116a 6176 612f 6c61 6e67 2f49
6e74 6567 6572 0100 0776 616c 7565 4f66
0100 1628 4929 4c6a 6176 612f 6c61 6e67
2f49 6e74 6567 6572 3b00 2100 0500 0a00
0000 0300 0000 0b00 0c00 0000 0200 0d00
0e00 0000 0900 0f00 1000 0000 0400 0100
1100 1200 0100 1300 0000 4200 0200 0100
0000 102a b700 012a 1202 b500 032a 08b5
0004 b100 0000 0200 1400 0000 0e00 0300
0000 0600 0400 0700 0a00 0800 1500 0000
0c00 0100 0000 1000 1600 1700 0000 0900
1800 1900 0100 1300 0000 5700 0200 0200
0000 17bb 0005 59b7 0006 4c2b 1008 b600
0710 14b8 0008 b300 09b1 0000 0002 0014
0000 0012 0004 0000 000b 0008 000c 000e
000d 0016 000e 0015 0000 0016 0002 0000
0017 001a 001b 0000 0008 000f 001c 0017
0001 0001 001d 001e 0001 0013 0000 003e
0002 0002 0000 0006 2a1b b500 04b1 0000
0002 0014 0000 000a 0002 0000 0011 0005
0012 0015 0000 0016 0002 0000 0006 0016
0017 0000 0000 0006 000d 000e 0001 0008
001f 0012 0001 0013 0000 0021 0001 0000
0000 0009 100a b800 08b3 0009 b100 0000
0100 1400 0000 0600 0100 0000 0900 0100
2000 0000 0200 21

字節碼解讀

cafe babe 魔數
00 00 00 34 魔數之後的4個字節為版本信息,前兩個字節表示minor version(次版本號),後兩個字節表示major version(主版本號)
00 2f content pool 為47表示有46個常量

0a 代表值為10 Methodref_info 這個常量 
00 0a 代表constant_class_info 索引為#10
00 22   代表constant_nameAndType_info索引為#34

08 代表String_info 
00 23 代表索引#35

09 代表Fieldref
00 05 代表constant_class_info 索引為#5
00 24 代表constant_nameAndType_info索引為#36

09 代表Fieldref
00 05  代表constant_class_info 索引為#5
00 25  代表constant_nameAndType_info索引為#37

07 代表class_info
00 26 代表權限定名索引 #38

0a 代表Methodref_info  
00 05 代表constant_class_info 索引為#5
00 22 代表constant_nameAndType_info索引為#34

0a 代表Methodref_info
00 05 代表constant_class_info 索引為#5
00 27 代表constant_nameAndType_info索引為#39

0a 代表Methodref_info
00 28 代表constant_class_info 索引為#40
00 29 代表constant_nameAndType_info索引為#41

09 代表Fieldref
00 05 代表constant_class_info 索引為#5
00 2a 代表constant_nameAndType_info索引為#42

07 代表class_info
00 2b 代表權限定名索引 #38

01 代表utf8(acsii碼轉換可以去(http://www.ab126.com/goju/1711.html#ecms)查看)
00 03 代表長度為3
73 74 72 代表str

01 代表utf8
00 12 代表長度為18
4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b
表示 L j a v a / l a n g / S t r i n g ;

01 代表utf8
00 01 代表長度為1
78 代表x

01 代表utf8
00 01 代表長度為1
49 代表l

01 代表utf8
00 02 代表長度為2
69 6e 代表in

01 代表utf8
00 13 代表長度為19
4c 6a 61 76 61 2f 6c 61 6e 67 2f 49 6e 74 65 67 65 72 3b
代表:L j a v a / l a n g / I n t e g e r ;

01 代表utf8
00 06 代表長度為6
3c 69 6e 69 74 3e
代表:< i n i t >

01 代表utf8
00 03 代表長度為3
28 29 56 代表:( ) V

01 代表utf8
00 04 代表長度為4
43 6f 64 65 代表:code

01 代表utf8
00 0f 代表長度為15
4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65
代表:L i n e N u m b e r T a b l e

01 代表utf8
00 12 代表長度為18
4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65
代表:LocalVariableTable

01 代表utf8
00 04 代表長度為4
74 68 69 73 代表:this

01 代表utf8
00 16 代表長度為22
4c 6a 76 6d 2f 62 79 74 65 63 6f 64 65 2f 4d 79 54 65 73 74 32 3b
代表:L j v m / b y t e c o d e / M y T e s t 2 ;

01 代表utf8
00 04 代表長度為4
6d 61 69 6e 代表:main

01 代表utf8
00 16 代表長度為22
28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
代表:( [ L j a v a / l a n g / S t r i n g ; ) V

01 代表utf8
00 04 代表長度為4
61 72 67 73 代表:a r g s

01 代表utf8
00 13 代表長度為19
5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b
代表: [Ljava/lang/String;

01 代表utf8
00 07 代表長度為7
6d 79 54 65 73 74 32 代表:myTest2

01 代表utf8
00 04 代表長度為4
73 65 74 58 代表:setX

01 代表utf8
00 04 代表長度為4
28 49 29 56 代表:(I)V

01 代表utf8
00 08 代表長度為8
3c 63 6c 69 6e 69 74 3e 代表:<clinit>

01 代表utf8
00 0a 代表長度為10
53 6f 75 72 63 65 46 69 6c 65 代表:SourceFile

01 代表utf8
00 0c 代表長度為12
4d 7954 6573 7432 2e6a 6176 61 代表:MyTest2.java

0c 代表:nameAndType_info
0011 代表:字段或方法名常量項描述符索引 #17
0012 代表:字段或方法名修飾符常量項索引 #18

01 代表utf8
00 07 代表長度為7
57 656c 636f 6d65 代表:Welcome

0c 代表:nameAndType_info
00 0b 代表:字段或方法名常量項描述符索引 #11
00 0c 代表:字段或方法名修飾符常量項索引 #12

0c 代表:nameAndType_info
00 0d  代表:字段或方法名常量項描述符索引 #13
00 0e  代表:字段或方法名修飾符常量項索引 #14

01 代表utf8
00 14 代表長度為20
6a 766d 2f62 7974 6563 6f64 652f 4d79 5465 7374 32
代表:jvm/bytecode/MyTest2

0c 代表:nameAndType_info
001d 代表:字段或方法名常量項描述符索引 #16+13=29
001e  代表:字段或方法名修飾符常量項索引 #16+14=30

07 代表:class_info
00 2c 限定名常量索引 #16*2+12=44

0c 代表:nameAndType_info
00 2d   代表:字段或方法名常量項描述符索引 #32+13=45
00 2e  代表:字段或方法名修飾符常量項索引 #32+ 14=46

0c 代表:nameAndType_info
00 0f   代表:字段或方法名常量項描述符索引 #15
00 10  代表:字段或方法名修飾符常量項索引 #16

01 代表utf8
00 10 代表長度為16
6a61 7661 2f6c 616e 672f 4f62 6a65 6374
代表:java/lang/Object

01 代表utf8
00 11 代表長度為17
6a 6176 612f 6c61 6e67 2f49 6e74 6567 6572
代表:java/lang/Integer

01 代表utf8
00 07 代表長度為7
76 616c 7565 4f66 代表:valueOf

01 代表utf8
00 16 代表長度為22
28 4929 4c6a 6176 612f 6c61 6e67 2f49 6e74 6567 6572 3b
代表:(I)Ljava/lang/Integer;

00 21 Access flag 表示ACC_PUBLIC 與ACC_SUPER取的並集

00 05 This Class Name 表示的一個索引指的是常量池第5個常量
00 0a This Super Name 表示的一個索引指的是常量池第10個常量

00 00 表示沒有實現接口

Fields
00 03 表示屬性的數量,表示有3個字段
00 00 表示修飾符access_flag 表示沒有修飾符
00 0b name_index 名字的索引#11 str
00 0c descriptor_index 描述符的索引 #12 Ljava/lang/String;
00 00 表示attributes_count為0,也就沒有attributes_info

00 02 表示修飾符access_flag 表示private
00 0d name_index 名字的索引#13 x
00 0e descriptor_index 描述符的索引 #14 i
00 00 表示attributes_count為0,也就沒有attributes_info

00 09 表示修飾符access_flag 表示public static
00 0f name_index 名字的索引#15 in
00 10 descriptor_index 描述符的索引 #16  Ljava/lang/Integer;
00 00 表示attributes_count為0,也就沒有attributes_info

Method
00 04 代表有4個方法,包含了自動生成的默認構造器
00 01 代表是一個public的方法
00 11 代表是name_index  #17 <init>
00 12 代表是descriptor_index #18 ()V
00 01 代表是attribute_count,有一個屬性
method attribute
00 13 代表屬性名的索引attribute_name_index #19 Code
00 00 00 42 attribute_length  66個字節長度
00 02 max_stack
00 01 max_local 局部變量最大值
00 00 00 10 code_length 方法的代碼長度 16個字節

2a b700 012a 1202 b500 032a 08b5 0004 b1
實際上就是對應著下面的助記符
2a -> aload_0
b7 -> invokespecial  00 01 lang/Object."<init>":()V
12 -> ldc(從常量池加載一個常量) 02 #2  Welcome
b5 -> putfield 00 03 #3 jvm/bytecode/MyTest2.str
08 -> iconst_5 
b1 -> return

exception
00 00

attributes
00 02 attribute_count; 表示有兩個屬性
00 14 屬性的索引 #20 LineNumberTable
00 00 00 0e attribute_length 14個字節
00 0300 0000 0600 0400 0700 0a00 08
00 03 表示有三對兩兩映射偏移量
00 00  -> 00 06 表示偏移量為0映射到行號為6
00 04 -> 00 07 表示偏移量為4映射到行號為7
00 0a -> 00 08 表示偏移量為10映射到行號為8

00 15 第21個屬性的索引 #21 LocalVariableTable
00 0000 0c 表示LocalVariableTable所占的字節長度
00 0100 0000 1000 1600 1700 00
00 01 局部變量的個數
00 00   局部變量開始的位置
00 10 局部變量結束的位置
00 16 局部變量索引 #22  this
00 17 索引 #23 Ljvm/bytecode/MyTest2;
00 00 用來做校驗檢查的

第二個方法:
00 09 表示public static
00 18 代表是name_index #24  main
00 19 代表是descriptor_index #25  ([Ljava/lang/String;)V
00 01 代表是attribute_count,有一個屬性
method attribute
00 13 代表屬性名的索引attribute_name_index #19 code
00 0000 57 attribute_length  87個字節長度
00 02 max_stack
00 02 max_local 局部變量最大值
00 0000 17 code_length 方法的代碼長度 23個字節 
bb 0005 59b7 0006 4c2b 1008 b600 0710 14b8 0008 b300 09b1
實際上就是對應著下面的助記符
bb -> new  index: 00 05 jvm/bytecode/MyTest2
59 -> dup  Duplicate the top operand stack value
b7 -> invokespecial  index:  00 06 jvm/bytecode/MyTest2."<init>":()V
4c -> astore_1 Storereferenceinto local variable
2b -> aload_1 
10 -> bipush
08 -> iconst_5
b6 -> invokevirtual index:00 07 jvm/bytecode/MyTest2.setX:(I)V
10 -> bipush
14 -> ldc2_w Push long or double from run-time constant pool index:b8 00  java/lang/Integer
b8 ->  invokestatic.  index: 0008 java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
b3 -> putstatic index: 00 09 jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
 b1 -> return

exception
00 00

attributes
00 02 attribute_count; 表示有兩個屬性
00 14 屬性的索引 #20  LineNumberTable
0000 0012 attribute_length 18個字節
0004 0000 000b 0008 000c 000e 000d 0016 000e
00 04 表示有4對兩兩映射偏移量
0000 000b 表示偏移量為0映射到行號為11
0008 000c 表示偏移量為8映射到行號為12
000e 000d 表示偏移量為14映射到行號為13
0016 000e 表示偏移量為22映射到行號為14

00 15 第二個屬性的索引 #21 LocalVariableTable
0000 0016 表示LocalVariableTable所占的字節長度 22
0002 0000 0017 001a 001b 0000 0008 000f 001c 0017 0001
00 02 局部變量的個數
00 00   局部變量1開始的位置
00 17 局部變量1長度 23
00 1a 局部變量1 索引 #26 
00 1b 局部變量1 描述符索引 #27  [Ljava/lang/String;
00 00 第一個索引結束
00 08 局部變量2開始的位置
00 0f 局部變量1長度 15
00 1c 局部變量1 索引 #28 myTest2
00 17 局部變量1 描述符索引 #23  Ljvm/bytecode/MyTest2;
00 01 第二個索引結束

第三個方法:
0001 public
001d 表示索引#29 setX
001e 表示索引#30 (I)V
0001 代表是attribute_count,有一個屬性
0013 代表屬性名的索引attribute_name_index  code
0000 003e code_length 方法的代碼長度 62個字節
00 02 max_stack
00 02 max_local
00 00 00 06 code_length 方法的代碼長度 6個字節
2a1b b500 04b1
2a 1b b5 00 02 b1
2a -> aload_0
1b -> iload_1
b5 -> putfield
00 02 表示第二常量
b1 -> return 

attributes
00 02 attribute_count; 表示有兩個屬性
0014  索引指向第20個常量 LineNumberTable
0000 000a attribute_length 10個字節
0002 0000 0011 0005 0012
00 02 表示有兩個對應關系
00 00 00 11 偏移量為0的對應的是11行
00 05 00 12 偏移量為5的對應的是12行

00 15 第二個屬性的索引 #21 LocalVariableTable
00 00 00 16 表示LocalVariableTable所占的字節長度 22個
0002 0000 0006 0016 0017 0000 0000 0006 000d 000e 0001
00 02 局部變量的個數
00 00   局部變量開始的位置
00 06 局部變量結束的位置
00 16 局部變量索引的位置  #22 this
00 17 局部變量索引的位置  #23 Ljava/lang/Integer;

00 00   局部變量開始的位置
00 06 局部變量結束的位置
00 0d 局部變量索引的位置  #13 x
00 0e 局部變量索引的位置  #14 I

第四個方法:
0008 : 代表public
001f : 表示索引#31  <clinit>
0012 : 表示索引#18  ()V
00 01: 代表是attribute_count,有一個屬性
0013 代表屬性名的索引attribute_name_index  code
0000 0021 code_length 方法的代碼長度 33個字節
0001  max_stack
0000 max_local
0000 0009 code_length 方法的代碼長度9個字節
100a b800 08b3 0009 b1
10 -> bipush  0a : 10
b8 -> invokestatic 00 08. #8 java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
b3 -> putstatic   0009. #9 jvm/bytecode/MyTest2.in:Ljava/lang/Integer;
b1 -> return 

attributes
00 01 attribute_count; 表示有1個屬性
00 14 索引指向第20個常量 LineNumberTable
00 0000 06 attribute_length 6個字節
00 0100 0000 09
00 01 表示有1個對應關系
00 00 00 09 偏移量為0的對應的是9行

Attributes
00 01
00 20 索引 #32 sourceFile
00 0000 02 源文件的長度
00 21 #33  MyTest2.java  

java學習筆記/jvm

深入理解JVM-java字節碼文件結構剖析(練習解讀字節碼)