Java面试笔记-JVM
修改Java字节码
在OpenJDK里有一个AsmTools
项目,用来生成正确的或者不正确的java .class
文件,主要用来测试和验证。
AsmTools
引入了两种表示.class
文件的语法:
JASM
用类似java本身的语法来定义类和函数,字节码指令则很像传统的汇编。
JCOD
整个
.class
用容器的方式来表示,可以很清楚表示类文件的结构。
重要的是两种语法的文件都是可以和.class
互相转换的。
在这里主要使用JASM
语法。
生成asmtools.jar
如果你的机器没有安装 Mercurial
,请先安装(Mericurial 类似 Git 和 SVN,是一个分布式版本控制系统,使用 Python 编写,OpenJDK 就托管在 Mercurial 平台上)
然后执行以下命令:
// Clone代码
hg clone ://hg.openjdk.java.net/code-tools/asmtools
// 编译
cd asmtools/build
ant
即可得到asmtools.jar文件。
准备一个Example
Foo.java
public class Foo {
public static void main(String[] args) {
boolean flag = true;
if (flag) System.out.println("Hello, Java!");
if (flag == true) System.out.println("Hello, JVM!");
}
}
javac Foo.java
命令生成Foo.class文件,使用JD-GUI打开内容如下:
import java.io.PrintStream;
public class Foo
{
public static void main(String[] paramArrayOfString)
{
int i = 1;
if (i != 0) {
System.out.println("Hello, Java!");
}
if (i == 1) {
System.out.println("Hello, JVM!");
}
}
}
java Foo
命令运行Foo.class文件输出结果:
Hello, Java!
Hello, JVM!
由class文件生成jasm文件
如下命令将class文件中的内容转换成对应的jasm语法:
java -jar asmtools.jar jdis Foo.class
上面输出的内容会直接打印在终端,当然你也可以把它输入到文件中:
java -jar asmtools.jar jdis Foo.class > Foo.jasm
Foo.jasm 文件内容如下:
super public class Foo
version 52:0
{
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 2
{
iconst_1;
istore_1;
iload_1;
ifeq L14;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello, Java!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
L14: stack_frame_type append;
locals_map int;
iload_1;
iconst_1;
if_icmpne L27;
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello, JVM!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
L27: stack_frame_type same;
return;
}
} // end Class Foo
为了将 Foo.class 中的 int i = 1;
修改成 int i = 2;
,我们需要替换 Foo.jasm 文件中的 iconst_1
为 iconst_2
。
由jasm文件生成class文件
执行如下命令:
java -jar asmtools.jar jasm Foo.jasm
这时再用 JD-GUI 打开 Foo.class 文件,内容如下:
import java.io.PrintStream;
public class Foo
{
public static void main(String[] paramArrayOfString)
{
int i = 2;
if (i != 0) {
System.out.println("Hello, Java!");
}
if (i == 1) {
System.out.println("Hello, JVM!");
}
}
}
看到 i 的确由 1 变成 2 了。
java Foo
输出内容如下:
Hello, Java!
总结
其实就两个命令:
- 由 class 文件生成 jasm 文件:
java -jar asmtools.jar jdis Foo.class > Foo.jasm
- 由 jasm 文件生成 class 文件:
java -jar asmtools.jar jasm Foo.jasm
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!