我正在尝试通过删除条件跳转来防止条件跳转无效:
if(1 > 10) {
return;
}
因此,我决定创建一个BasicInterpreter
来检查跳转的帧是否为null
,如果是,请将其删除。而且它不是null
,因此不会将其检测为无用的。
无效的代码:
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
if(frames[i] == null) {
System.out.println("This jump is useless");
}
}
}
}
然后,我尝试获取一些堆栈值进行手动计算,但没有成功(我发现,但是我无法移植代码以在跳转ASM Get exact value from stack frame上使用它:)
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
// getStackSize() returns 2 so -> 0 and 1
frames[i].getStack(0); // this is probably 1
frames[i].getStack(1); // this is probably 10
// but it returns a BasicValue so I can't check if the code works or not (we cannot get values)
}
}
}
我最后尝试做的是获取跳转使用的指令大小以将其删除(当然,它不会检测它是否是无用的代码,但我至少可以删除它)。
实际上,我尝试创建一个返回常量int的方法,以便我可以检测是否在跳转指令中调用了getValue(如果检测到调用,则删除跳转指令,当然还要删除跳转本身) ):
示例:
if(1 > getValue()) { //getValue() returns 10
return;
}
代码:
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
ArrayList<AbstractInsnNode> nodesR = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
ArrayList<AbstractInsnNode> toRemove = new ArrayList<>();
for (int ia = 1; ia < frames[i].getMaxStackSize() + 2; ia++) { // I started from 1 and added 2 to getMaxStackSize because I wasn't getting all the instructions
toRemove.add(mn.instructions.get(i - ia));
}
toRemove.add(mn.instructions.get(i)); // I add the jump to the list
for (AbstractInsnNode aaa : toRemove) {
if (aaa.getOpcode() == INVOKESTATIC) { // the invokestatic is getValue
for (AbstractInsnNode aaas : toRemove) {
nodesR.add(aaas);
}
break;
}
}
}
}
}
for (AbstractInsnNode aaas : nodesR) {
mn.instructions.remove(aaas);
}
} catch (AnalyzerException e) {
e.printStackTrace();
}
这段代码可能很可怕并且没有经过优化,但是我尝试了很多事情,但都没有成功。 getMaxStackSize()不会返回100%正确的数字(有时它不进行加法运算,因此会删除标签等指令)。
我要做什么:
通过方法进行分析,并检查条件跳转是否始终为false(因此将永远不会执行其中的代码),然后将其删除。 我尝试了两种不同的方式:
BasicInterpreter
检查此跳转是否将以恒定值执行,然后尝试查看它是否始终为假getValue()
,该方法返回10,并比较是否小于1),然后将其删除
我不明白的地方:BasicInterpreter
测试两个常量int是否总是返回相同的结果