概述
1. 关于asmtools.jar
用途:使得 “.class文件 -> 字节码指令(类似汇编语言)文件 -> .class文件”,并可以修改“字节码指令文件” 改变一个“.class文件”的运行结果。并重新生成class文件
2. 获取方式asmtools.jar
环境准备:JDK version 8.0, Ant version 1.8 or later, mercurial
下载:hg clone http://hg.openjdk.java.net/code-tools/asmtools
编译:cd asmtools/build && ant 上面是下载打包方式,如果图懒省事,直接使用别人打包好的即可:
3. 使用案例
以郑雨迪老师在“深入拆解JVM”专栏https://time.geekbang.org/column/article/11289 中对boolean类型在jvm中的类型为例示例如何使用:
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 文件, java Foo 命令运行 Foo.class 文件输出结果:
Hello, Java!
Hello, JVM!
由 class 文件生成 jasm 文件
如下命令将 class 文件中的内容转换为对应的 jasm 语法
java -jar asmtools.jar jdis Foo.class
执行结果为:
package
foo;
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
可以到看到boolean在JVM实际上是作为int处理的
iconst_1 将1压入操作数栈
istore_1 将操作数栈顶保存至局部变量表1位置,
iload_1 再讲局部变量表1 位置加载到操作数栈顶
ifeq L14 判断栈顶位置是否为0 为零则跳转到L14
我们来尝试修改 将压入的1 改为2 看看什么效果
linux下java -jar asmtools.jar jdis Foo.class > Foo.jasm将上述结果输出到文件中。window下直接新建文件将上一个命令输出结果内容拷贝过去即可
将 Foo.class 中的 int i = 1; 修改成 int i = 2;,我们只需要替换 Foo.jasm 文件中的 iconst_1 为 iconst_2
由jsam文件生成class文件
将修改过后的Foo.jasm 执行命令生成class文件
java -jar asmtools.jar jasm Foo.jasm
此时再执行 java Foo 输出:
Hello, Java!
可见字节码已经被修改,至于为何第一个位false第二个为true,解释为:
ifeq 指令的逻辑是 判断栈顶元素是否为0 不为零纪委true了所以改为2 依然为true。
if_cmpne做整数比较,iconst_1是否等于flag(1)比较失败。
扩展
public class Foo {
static boolean boolValue;
public static void main(String[] args) {
boolValue = true; // 将这个true替换为2或者3,再看看打印结果
if (boolValue) System.out.println("Hello, Java!");
if (boolValue == true) System.out.println("Hello, JVM!");
}
}
结果:
当替换为2的时候无输出
当替换为3的时候打印HelloJava及HelloJVM
是因为将boolean 保存在静态域中,指定了其类型为’Z’,当修改为2时取低位最后一位为0,当修改为3时取低位最后一位为1
则说明boolean的掩码处理是取低位的最后一位
4.总结
主要就两条命令
由 class 文件生成 jasm 文件:java -jar asmtools.jar jdis Foo.class > Foo.jasm
由 jasm 文件生成 class 文件:java -jar asmtools.jar jasm Foo.jasm
最后
以上就是激动花瓣为你收集整理的asmtools的使用的全部内容,希望文章能够帮你解决asmtools的使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复