ASM简介(一)

作者: 千里山南 | 来源:发表于2016-07-28 16:32 被阅读741次

之前简单研究过ASM这个字节码修改框架,最近要用到,故简单复习下。顺便翻译下官方文档(翻译主要是给自己看的,因此比较随意,自己看一眼就明白的直接跳过了,大家权且当作是读书笔记吧)。

字节码修改的必要性

  • 字节码的分析、翻译及自动生成很常见
  • 直接作用于class文件的优势是,可以适用于闭源软件商业软件等拿不到源码的修改翻译,并且可以在运行时修改字节码,其操作对于源代码开发者是透明的。

ASM的优势

  • 足够小足够快
  • API足够好用
  • 有Eclipse及Intellij插件
  • 应用广泛
  • 开源协议宽泛

概览

ASM设计用于字节码的改写、生成。其有两套API一套基于访问者模式、一套基于树的数据结构。基于访问者模式的api,类中的每个数据结构都是一个Event,类的生成同样基于这样的Event。基于树的数据结构的api是面向对象的一种设计,类被表示为一个对象。这两套api的区别类似xml解析中的SAX和DOM。两套api都是对同一个class操作的,如果用户需要修改相关联的类需要自己手动管理。

功能介绍

asm.jar 包含时间模式的API,适用于class文件的读写。
asm-util.jar 包含一些工具类,基于base api 用于协助开发调试
asm-commons.jar 提供了一些很有用的预定义基于事件的类转换器
asm-tree.jar 提供了基于对象的api并提供两种api的转化
asm-analysis.jar 提供了基于对象api的类的分析框架类

字节码文件格式概览

  • 描述类访问控制权限,类名,父类,接口和注解
  • 每个被声明的成员变量,同样包括访问控制权限、名称、类型、注解
  • 方法及构造函数,包括访问控制权限,名称、名称、返回值类型、参数类型、注解等。同时还包含方法体(一系列jvm指令)

类源码和字节码区别:每个class文件只包含一个类,没有注释。没有package 和 import部分,所有的类型必须使用全名。另一个重要的区别在于,编译后的字节码有一个常量存放区。存放着类中出现的所有的数字、字符串、类型常量。这些常量只被定义一次,被类的其他部分通过索引引用。不过使用ASM的话常量定义区对我们而言是透明的。另一个区别在于源文件和class文件中对类型的引用方式不同。
class 文件的结构如下

Modifiers, name, super class, interfaces
Constant pool: numeric, string and type constants
Source file name (optional)
Enclosing class reference
Annotation*
Attribute*
Inner class* Name
Field* Modifiers, name, type
Annotation*
Attribute*
Method* Modifiers, name, return and parameter types
Annotation*
Attribute*
Compiled code

bytecode中type表示如下:类似jni接口

Java type Type descriptor
boolean Z
char C
byte B
short S
int I
float F
long J
double D
Object Ljava/lang/Object;
int[] [I
Object[][] [[Ljava/lang/Object;

方法描述也类似jni

Method declaration in source file Method descriptor
void m(int i, float f) (IF)V
int m(Object o) (Ljava/lang/Object;)I
int[] m(int i, String s) (ILjava/lang/String;)[I
Object m(int[] i) ([I)Ljava/lang/Object;

接口和组件

class的生成和转换时基于ClassVisitor抽象类的。该类的每个方法都对应class的一个结构。简单的结构对应的方法入参为结构的描述,方法返回void即可。复杂的使用一个init方法来访问,并且返回一个描述改结构的visitor类。例如visitAnnotation、visitField\visitMethod需要返回AnnotationVisitor、FieldVisitor、MethodVisitor。这样整个结构可以被递归的调用

public abstract class ClassVisitor { 
    public ClassVisitor(int api); 
    public ClassVisitor(int api, ClassVisitor cv); 
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces); 
            public void visitSource(String source, String debug); 
            public void visitOuterClass(String owner, String name, String desc); 
    AnnotationVisitor visitAnnotation(String desc, boolean visible); 
    public void visitAttribute(Attribute attr); 
    public void visitInnerClass(String name, String outerName, String innerName, int access); 
    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value); 
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions); 
    void visitEnd(); 
}

ClassVisitor方法调用必须要按照以下顺序:visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* ( visitInnerClass | visitField | visitMethod )* visitEnd

基于ClassVisitor ASM提供了 ClassReader来解析字节流格式的class. ClassWriter 用于生成二进制格式的class. ClassVisitor 可以看作是Event的过滤器

相关文章

  • ASM简介(一)

    之前简单研究过ASM这个字节码修改框架,最近要用到,故简单复习下。顺便翻译下官方文档(翻译主要是给自己看的,因此比...

  • ASM 简介

    前言 很早之前就写过面向切面的编程思想,主要学习了AOP的思想(参考:AOP简介)以及使用 AspectJ 实现简...

  • ASM简介(二)

    访问class 访问一个class的最简单的方式是声明一个ClassReader类,然后复写其中的方法。Class...

  • ASM简介(三)

    使用修改类 如果我们一次性修改的类比较多,如果想使用这些类,我们可以使用java.lang.instrument....

  • ASM简介(四)

    函数 我们在使用ASM相关API对函数进行操作之前,我们需要了解函数在字节码的存储格式及其执行模型。 执行模型 我...

  • ASM简介(六)

    TreeAPI Class ASM中修改生成class主要依赖ClassNode类 生成class时我们只需构造对...

  • ASM简介(五)

    元数据 泛型 泛型在运行时并不会被字节码指令使用,但可以被反射API拿到,可以被编译器使用。由于向前兼容的原因,泛...

  • Android编译时技术04 --- ASM

    部分内容来自:https://www.jianshu.com/p/29e9b03c0796 一.ASM简介 ASM...

  • 工具开发,字节码技术

    简介 几个对比: https://segmentfault.com/a/1190000009956534ASM(A...

  • ASM Core Api 详解

    前言 前面一篇文章 ASM 简介 对 ASM 框架做了简单的介绍。 本篇文章主要对该框架的 Core Api 其中...

网友评论

    本文标题:ASM简介(一)

    本文链接:https://www.haomeiwen.com/subject/hhmajttx.html