《深入理解Java虚拟机》-(实战)练习修改class文件
这是一篇修改class文件的文章。注释并不完全,要抓住这次练习的目的:
boolean在虚拟机中是以何种方式解读的
好的,开始我的表演
1.安装asmtools.jar(本文尾部有步骤)
2.编写一个java文件,并编译,执行 2.1 Foo.java
1 public class Foo { 2 public static void main(String[] args) { 3 boolean flag = true; 4 if (flag) { 5 System.out.println("Hello, Java!"); 6 } 7 if (flag == true) { 8 System.out.println("Hello, JVM!"); 9 } 10 } 11 }
View Code
2.2 编译并运行
[root@localhost tmp]# javac Foo.java [root@localhost tmp]# java Foo Hello, Java! Hello, JVM!
3.查看编译后的java文件,class (注意看黄色部分的变化)
[root@localhost tmp]# javap -verbose Foo Classfile /usr/local/asmtools-7.0-build/binaries/lib/tmp/Foo.class Last modified Aug 12, 2019; size 493 bytes MD5 checksum d51944604c5b4e45cb895501910347ea Compiled from "Foo.java" public class Foo minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #7.#17 // java/lang/Object."<init>":()V #2 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #20 // Hello, Java! #4 = Methodref #21.#22 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = String #23 // Hello, JVM! #6 = Class #24 // Foo #7 = Class #25 // java/lang/Object #8 = Utf8 <init> #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 main #13 = Utf8 ([Ljava/lang/String;)V #14 = Utf8 StackMapTable #15 = Utf8 SourceFile #16 = Utf8 Foo.java #17 = NameAndType #8:#9 // "<init>":()V #18 = Class #26 // java/lang/System #19 = NameAndType #27:#28 // out:Ljava/io/PrintStream; #20 = Utf8 Hello, Java! #21 = Class #29 // java/io/PrintStream #22 = NameAndType #30:#31 // println:(Ljava/lang/String;)V #23 = Utf8 Hello, JVM! #24 = Utf8 Foo #25 = Utf8 java/lang/Object #26 = Utf8 java/lang/System #27 = Utf8 out #28 = Utf8 Ljava/io/PrintStream; #29 = Utf8 java/io/PrintStream #30 = Utf8 println #31 = Utf8 (Ljava/lang/String;)V { public Foo(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 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: iconst_1 //常量1入栈 1: istore_1 //把栈顶值存储到局部变量表下标为1的位置,即flag =1; 2: iload_1 //取局部变量表中下标为1的变量压栈 3: ifeq 14 //(jump if i == 0) 将栈顶值与0比较,如果相等,则跳入14步骤。 6: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 9: ldc #3 // String Hello, Java! 11: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: iload_1 //取局部变量表中下标为1的变量压栈 15: iconst_1 //常量1入栈 16: if_icmpne 27 //比较栈顶两个值,如果不相等,则跳转到27 19: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 22: ldc #5 // String Hello, JVM! 24: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 27: return LineNumberTable: line 3: 0 line 4: 2 line 5: 6 line 7: 14 line 8: 19 line 10: 27 StackMapTable: number_of_entries = 2 frame_type = 252 /* append */ offset_delta = 14 locals = [ int ] frame_type = 12 /* same */ } SourceFile: "Foo.java"
View Code
4.使用asmtools.jar修改class文件
[root@localhost tmp]# java -jar ../asmtools.jar jdis Foo.class > Foo.jasm.1 [root@localhost tmp]# ls Foo.class Foo.jasm.1 Foo.java [root@localhost tmp]# java -cp ../asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class > Foo.jasm.1 [root@localhost tmp]# awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_2")} 1' Foo.jasm.1 > Foo.jasm [root@localhost tmp]# ls Foo.class Foo.jasm Foo.jasm.1 Foo.java [root@localhost tmp]# java Foo Hello, Java! Hello, JVM!
5.再次编译,执行
[root@localhost tmp]# java -jar ../asmtools.jar jasm Foo.jasm [root@localhost tmp]# java Foo Hello, Java! [root@localhost tmp]# ls Foo.class Foo.jasm Foo.jasm.1 Foo.java
6.查看修改后的class文件
[root@localhost tmp]# javap -verbose Foo Classfile /usr/local/asmtools-7.0-build/binaries/lib/tmp/Foo.class Last modified Aug 12, 2019; size 431 bytes MD5 checksum 18cfb8b8b7d9d49e9ffce213e70c8898 Compiled from "Foo.jasm" public class Foo minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = String #10 // Hello, Java! #2 = String #11 // Hello, JVM! #3 = Fieldref #27.#12 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #8.#17 // java/lang/Object."<init>":()V #5 = Methodref #13.#30 // java/io/PrintStream.println:(Ljava/lang/String;)V #6 = Utf8 (Ljava/lang/String;)V #7 = Utf8 out #8 = Class #9 // java/lang/Object #9 = Utf8 java/lang/Object #10 = Utf8 Hello, Java! #11 = Utf8 Hello, JVM! #12 = NameAndType #7:#23 // out:Ljava/io/PrintStream; #13 = Class #15 // java/io/PrintStream #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 java/io/PrintStream #16 = Utf8 main #17 = NameAndType #29:#20 // "<init>":()V #18 = Utf8 SourceFile #19 = Utf8 println #20 = Utf8 ()V #21 = Utf8 StackMapTable #22 = Utf8 Foo.jasm #23 = Utf8 Ljava/io/PrintStream; #24 = Utf8 Code #25 = Class #26 // Foo #26 = Utf8 Foo #27 = Class #28 // java/lang/System #28 = Utf8 java/lang/System #29 = Utf8 <init> #30 = NameAndType #19:#6 // println:(Ljava/lang/String;)V { public Foo(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #4 // Method java/lang/Object."<init>":()V 4: return 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: iconst_2 //载入常量2入栈 1: istore_1 //把栈顶值存储到局部变量表下标为1的位置,即flag =2; 2: iload_1 //取局部变量表中下标为1的变量压栈 3: ifeq 14 6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 9: ldc #1 // String Hello, Java! 11: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: iload_1 //取局部变量表中下标为1的变量压栈 15: iconst_1 //常量1入栈 16: if_icmpne 27 //比较栈顶两个值,如果不相等,则跳转到27 19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 22: ldc #2 // String Hello, JVM! 24: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 27: return StackMapTable: number_of_entries = 2 frame_type = 252 /* append */ offset_delta = 14 locals = [ int ] frame_type = 12 /* same */ } SourceFile: "Foo.jasm"
附:asmtools.jar的安装(centos 6/7)
0.先cd进入需要安装到的目录地址 1. Mercurial是一种轻量级分布式版本控制系统,采用Python语言实现。
yum install hg
2. 版本是2.6.2,发现不是最新版,去官方下载centos 7最新版3.9.2
wget https://www.mercurial-scm.org/release/centos7/RPMS/x86_64/mercurial-3.9.2-1.x86_64.rpm
3.升级2.6.2 到3.9.2 (centos 6 我就没有用这一步。。)
rpm -Uvh mercurial-3.9.2-1.x86_64.rpm
4.安装ASMTOOLS.jar
hg clone http://hg.openjdk.java.net/code-tools/asmtools/ asmtools cd asmtools/build/ yum install ant ant //编译生成asmtools.jar
5.生成的jar位置:
[root@localhost lib]# ls asmtools.jar [root@localhost lib]# pwd /usr/local/asmtools-7.0-build/binaries/lib
相关文章