使用 asm 重建方法时的杂散指令
Stray instructions when reconstructing method using asm
我正在使用 asm 修改 MethodNode 的指令。我的代码从 methodNode.instructions 构建了一个图表。使用此图,我重新排列和删除指令。然后,我使用该图为 MethodNode 生成一个新的指令列表。问题是指令仍然具有 .getNext() 的值,这会导致图形中不再包含的杂散指令被添加到方法指令的末尾。这也会在将 InsnList 转换为数组时导致 ArrayIndexOutOfBoundsException。
示例:
初步说明:
L0
ALOAD 1
LDC 1784196469
INVOKEVIRTUAL dq.c (I)I
ISTORE 2
ILOAD 2
IFNE L1
GOTO L2
L3
RETURN
L1
ALOAD 0
ALOAD 1
ILOAD 2
BIPUSH 15
INVOKEVIRTUAL ac.f (Ldq;IB)V
GOTO L0
L2
GOTO L3
图形变化后。这些是清除列表后添加到 methodNode.instructions 的说明。
L0
ALOAD 1
LDC 1784196469
INVOKEVIRTUAL dq.c (I)I
ISTORE 2
ILOAD 2
IFNE L1
RETURN
L1
ALOAD 0
ALOAD 1
ILOAD 2
BIPUSH 15
INVOKEVIRTUAL ac.f (Ldq;IB)V
GOTO L0
在最后一条指令上调用 .getNext() 时,结果如下:
org.objectweb.asm.tree.LabelNode@7a0ac6e3
如您所见,添加的最后一条指令 (GOTO L0) 具有 .getNext()
的值
当这个MethodNode被保存然后反编译时,这是结果。有一个指向不存在的标签的杂散 GOTO 语句。
L1 {
aload1
ldc 1784196469 (java.lang.Integer)
invokevirtual dq c((I)I);
istore2
iload2
ifne L2
return
}
L2 {
aload0 // reference to self
aload1
iload2
bipush 15
invokevirtual ac f((Ldq;IB)V);
goto L1
goto L3
}
如果我要更改指令的顺序,如何重用该方法中的指令?这是一个错误还是我使用了 asm 错误?
InsnList
is a linked list of AbstractInsnNode
。 AbstractInsnNode
的每个实例都有一个名为 next
的指针,指向列表中的下一个节点。
重新排列列表中的节点时,您还需要注意这些指针。在您的例子中,GOTO L0
的节点最初指向 L2
,并且由于其 next
指针在重排期间未更新,所以它最后仍指向 L2
。
更新 next
指针似乎没有简单的解决方案。没有 setter 方法。 clear
方法不会这样做。 removeAll
方法不可见。
一些可能性可能是 (i) 使用 remove
从列表中删除所有节点,然后再使用它们;或 (ii) 为新列表构建新节点。
我正在使用 asm 修改 MethodNode 的指令。我的代码从 methodNode.instructions 构建了一个图表。使用此图,我重新排列和删除指令。然后,我使用该图为 MethodNode 生成一个新的指令列表。问题是指令仍然具有 .getNext() 的值,这会导致图形中不再包含的杂散指令被添加到方法指令的末尾。这也会在将 InsnList 转换为数组时导致 ArrayIndexOutOfBoundsException。
示例:
初步说明:
L0
ALOAD 1
LDC 1784196469
INVOKEVIRTUAL dq.c (I)I
ISTORE 2
ILOAD 2
IFNE L1
GOTO L2
L3
RETURN
L1
ALOAD 0
ALOAD 1
ILOAD 2
BIPUSH 15
INVOKEVIRTUAL ac.f (Ldq;IB)V
GOTO L0
L2
GOTO L3
图形变化后。这些是清除列表后添加到 methodNode.instructions 的说明。
L0
ALOAD 1
LDC 1784196469
INVOKEVIRTUAL dq.c (I)I
ISTORE 2
ILOAD 2
IFNE L1
RETURN
L1
ALOAD 0
ALOAD 1
ILOAD 2
BIPUSH 15
INVOKEVIRTUAL ac.f (Ldq;IB)V
GOTO L0
在最后一条指令上调用 .getNext() 时,结果如下:
org.objectweb.asm.tree.LabelNode@7a0ac6e3
如您所见,添加的最后一条指令 (GOTO L0) 具有 .getNext()
的值当这个MethodNode被保存然后反编译时,这是结果。有一个指向不存在的标签的杂散 GOTO 语句。
L1 {
aload1
ldc 1784196469 (java.lang.Integer)
invokevirtual dq c((I)I);
istore2
iload2
ifne L2
return
}
L2 {
aload0 // reference to self
aload1
iload2
bipush 15
invokevirtual ac f((Ldq;IB)V);
goto L1
goto L3
}
如果我要更改指令的顺序,如何重用该方法中的指令?这是一个错误还是我使用了 asm 错误?
InsnList
is a linked list of AbstractInsnNode
。 AbstractInsnNode
的每个实例都有一个名为 next
的指针,指向列表中的下一个节点。
重新排列列表中的节点时,您还需要注意这些指针。在您的例子中,GOTO L0
的节点最初指向 L2
,并且由于其 next
指针在重排期间未更新,所以它最后仍指向 L2
。
更新 next
指针似乎没有简单的解决方案。没有 setter 方法。 clear
方法不会这样做。 removeAll
方法不可见。
一些可能性可能是 (i) 使用 remove
从列表中删除所有节点,然后再使用它们;或 (ii) 为新列表构建新节点。