我是靠谱客的博主 激动花瓣,最近开发中收集的这篇文章主要介绍asmtools的使用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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的使用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部