日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java asm 中文文档_Java ASM3学习(3)

發(fā)布時(shí)間:2023/12/31 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java asm 中文文档_Java ASM3学习(3) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

MethodVisitor

ClassVisitor的visitMethod能夠訪問到類中某個(gè)方法的一些入口信息,那么針對(duì)具體方法中字節(jié)碼的訪問是由MethodVisitor來進(jìn)行的

訪問順序如下,其中visitCode和visitMaxs僅調(diào)用一次,標(biāo)志方法字節(jié)碼訪問的開始和結(jié)束

MethodVisitor如何獲得:

1.ClassReader中傳入的ClassVisitor中返回的MethodVisitor

2.直接調(diào)用ClassWriter.visitMethod返回MethodVisitor

創(chuàng)建ClassWriter的時(shí)候:

1.new ClassWriter(0)

自己計(jì)算幀、操作數(shù)棧大小和局部變量表大小,即自己調(diào)用visitMaxs

2.new ClassWriter(COMUPTE_MAXS)

自動(dòng)計(jì)算幀、操作數(shù)棧大小和局部變量表大小,但是仍需要調(diào)用visitMaxs,里面的參數(shù)自動(dòng)忽略,優(yōu)點(diǎn)是簡單,缺點(diǎn)是程序運(yùn)行性能降低(10%)

3.new ClassWriter(COMPUTE_FRAMES)

與2類似,改進(jìn)是不用再調(diào)用visitFrame,性能只下降2的一半

常用api:

visitFieldInsn : 訪問某個(gè)成員變量的指令,支持GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.

visitFrame :訪問當(dāng)前局部變量表和操作數(shù)棧中元素的狀態(tài),參數(shù)就是局部變量表和操作數(shù)棧的內(nèi)容

visitIincInsn : 訪問自增指令

visitVarInsn :訪問局部變量指令,就是取局部變量變的值放入操作數(shù)棧

visitMethodInsn :訪問方法指令,就是調(diào)用某個(gè)方法,支持INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.

visitInsn : 訪問無操作數(shù)的指令,例如nop,duo等等

visitTypeInsn:訪問type指令,即將一個(gè)類的全限定名作為參數(shù)然后new一個(gè)對(duì)象壓入操作數(shù)棧中

生成方法:

比如

package asm;public classbean {private intf;publicbean() {

}public void setF(intf) {this.f =f;

}public intgetF() {return this.f;

}

}

上面的getF方法就可以用其對(duì)應(yīng)的字節(jié)碼指令生成

假設(shè)mv是MethodVisitor,即:

mv.visitCode();//標(biāo)志開始訪問

mv.visitVarIn(ALOAD,0)

mv.visitFieldInsn(GETFIELD,"asm/beam","f","I")

mv.visitInsn(IRETURN)

mv.visitMaxs(1,1) //局部表量表和操作數(shù)棧的大小,只要一個(gè)this即可

mv.visitEnd

那么可以動(dòng)態(tài)的生成setF的方法體:

那么只需要定義一個(gè)ClassAdapter,由于要遍歷每個(gè)方法,因此在visitMethod處判斷方法名即可hook指定方法:

packageasm;importorg.objectweb.asm.ClassAdapter;importorg.objectweb.asm.ClassVisitor;importorg.objectweb.asm.MethodVisitor;importorg.objectweb.asm.Opcodes;public class ClassPrint extendsClassAdapter {publicClassPrint(ClassVisitor classVisitor) {super(classVisitor);

}

@Overridepublic MethodVisitor visitMethod(intvar1, String var2, String var3, String var4, String[] var5) {

System.out.println(var2);if (var2.equals("setFf")) {

MethodVisitor mv= this.cv.visitMethod(var1, var2, var3, var4, var5);

mv.visitVarInsn(Opcodes.ALOAD,0);

mv.visitVarInsn(Opcodes.ILOAD,1);

mv.visitFieldInsn(Opcodes.PUTFIELD,"asm/bean", "f", "I");

mv.visitInsn(Opcodes.RETURN);

mv.visitMaxs(2, 2);

mv.visitEnd();returnmv;

}return this.cv.visitMethod(var1, var2, var3, var4, var5);

}

}

生成結(jié)果如下:

結(jié)合if以及異常的字節(jié)碼指令分析:

還是以以下代碼為例,假設(shè)要為setFf生成代碼塊,先取其字節(jié)碼指令:

packageasm;public classbean {private intf;public void setFf(intf) {if(f>=0){this.f=f;

}else{throw newIllegalArgumentException();

}

}public intgetF(){returnf;

}

}

字節(jié)碼指令如下:

這里要引入棧映射幀的概念,就是表示在執(zhí)行某一條字節(jié)碼指令之前,幀的狀態(tài),即局部變量表和操作數(shù)棧的狀態(tài),不是每條字節(jié)碼前面都有棧映射幀,通常在有條件跳轉(zhuǎn)或無條件跳轉(zhuǎn)之后或者拋出異常之前,只要記住有這么個(gè)指令即可,具體怎么用可以查doc。ps:直接根據(jù)idea給出的字節(jié)碼指令來寫asm代碼即可

即對(duì)應(yīng)的重寫setFf的asm代碼為:

packageasm;import org.objectweb.asm.*;public class ClassPrint extendsClassAdapter {publicClassPrint(ClassVisitor classVisitor) {super(classVisitor);

}

@Overridepublic MethodVisitor visitMethod(intvar1, String var2, String var3, String var4, String[] var5) {

System.out.println(var2);if (var2.equals("setFf")) {

MethodVisitor mv= this.cv.visitMethod(var1, var2, var3, var4, var5);

mv.visitVarInsn(Opcodes.ILOAD,1); //f入棧

Label l1 = newLabel();

mv.visitJumpInsn(Opcodes.IFLT,l1);//彈出f和0比較,此時(shí)棧空,到label1

mv.visitVarInsn(Opcodes.ALOAD,0);//壓入this

mv.visitVarInsn(Opcodes.ILOAD,1); //壓入f

mv.visitFieldInsn(Opcodes.PUTFIELD,"asm/bean","f","I"); //彈出this和f,賦值this.f=f

Label l2 = new Label(); //聲明label

mv.visitJumpInsn(Opcodes.GOTO,l2); //跳轉(zhuǎn)關(guān)聯(lián)label2

mv.visitLabel(l1);//label1起始

mv.visitFrame(Opcodes.F_SAME,2,null,0,null); //訪問當(dāng)前幀狀態(tài)

mv.visitTypeInsn(Opcodes.NEW,"java/lang/IllegalArgumentException");//new異常,分配內(nèi)存但不做初始化操作

mv.visitInsn(Opcodes.DUP);//復(fù)制棧里元素(對(duì)象地址),再次壓入

mv.visitMethodInsn(Opcodes.INVOKESPECIAL,"java/lang/IllegalArgumentException","","()V");//彈出一個(gè)對(duì)象所在地址,進(jìn)行初始化操作,構(gòu)造函數(shù)默認(rèn)為空,此時(shí)棧大小為1

mv.visitInsn(Opcodes.ATHROW);//此時(shí)棧中對(duì)象已經(jīng)進(jìn)行初始化,所以彈出該值,即拋出異常

mv.visitLabel(l2);//label2起始

mv.visitFrame(Opcodes.F_SAME,2,null,0,null);//訪問當(dāng)前幀狀態(tài)

mv.visitInsn(Opcodes.RETURN);//返回

mv.visitMaxs(2, 2);//設(shè)置局部表量表和操作數(shù)棧大小

mv.visitEnd();//訪問結(jié)束

returnmv;

}return this.cv.visitMethod(var1, var2, var3, var4, var5);

}

}

asm不同版本差別

調(diào)用思想不變,做好替換即可

參考:

ASM4使用指南

總結(jié)

以上是生活随笔為你收集整理的java asm 中文文档_Java ASM3学习(3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。