1.获取asmtools.jar
(1)在http://hg.openjdk.java.net/code-tools/asmtools/下载zip包
(2)解压下载好的zip包
(3)进入build目录,在此目录下打开命令窗口,执行ant
命令
(4)在asmtools根路径下会生成asmtools-7.0-build文件夹,在\binaries\lib路径下就是jar包了。
2.实验
输入以下指令:
echo '
public class Foo {
public static void main(String[] args) {
boolean boolValue = true;
if (boolValue) System.out.println("Hello, Java!");
if (boolValue == true) System.out.println("Hello, JVM!");
}
}' > Foo.java
$ javac Foo.java
$ java Foo ##查看第一次编译的结果 Hello,Java! Hello, JVM!
$ java -cp /path/to/asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class > Foo.jasm.1##将.class文件变成jasm格式
$ awk 'NR==1,/iconst_1/{sub(/iconst_1/, "iconst_2")} 1' Foo.jasm.1 > Foo.jasm ##修改jasm文件并存储到另一个jasm格式的class文件
$ java -cp /path/to/asmtools.jar org.openjdk.asmtools.jasm.Main Foo.jasm ##将修改后jasm格式的class文件生成.class文件
$ java Foo ##查看修改后的结果 Hello, Java!
3.结果原因:
(1)先来看一下Foo.class没修改前的字节码:
super public class Foo
version 52:0
{
static Field boolValue:Z;
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public static Method main:"([Ljava/lang/String;)V"
stack 2 locals 1
{
iconst_1;
putstatic Field boolValue:"Z";
getstatic Field boolValue:"Z";
ifeq L18; //如果不是0,跳到L18执行(也就是不执行打印)
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello, Java!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
L18: stack_frame_type same;
getstatic Field boolValue:"Z";
iconst_1;
if_icmpne L33;//如果不相等,跳到L33执行
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello, JVM!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
L33: stack_frame_type same;
return;//直接return
}
} // end Class Foo
(2)Java虚拟机规范中,boolean类型被映射成int类型,true=1,false=0,实际如下:
public class Foo
{
public static void main(String[] paramArrayOfString)
{
int i = 1;
if (i != 0)
System.out.println("Hello, Java!");
if (i != 1)
return;
System.out.println("Hello, JVM!");
}
}
当我们把i改成2时,i!=1,所以直接return,不会输出第二个。
4.部分字节码解释
ifeq:弹出栈顶元素,并将之和0比较
if_icmpne:比较栈顶两个元素
ps:
jasm也是一种class文件的语法,可以和class互相转换。接受jasm格式的文件,生成.class文件
jdis是反汇编程序,接受.class文件,输出翻译成jasm格式的文件