提问人:MeBigFatGuy 提问时间:9/22/2023 更新时间:9/22/2023 访问量:30
使用 java 的 asm.jar 查找当前指令是否处于循环中
Finding if the current instruction is in a loop using java's asm.jar
问:
我想确定当前指令是否在循环中。
我对 asm 如何做到这一点感到困惑,
- Backward Labels 偏移量不会确定,直到您命中分支到它们的语句
- 似乎没有办法知道当前指令的偏移量
因此,您可以清楚地确定指令是在循环之前还是在循环中,但它可能是
statement in question
for () {
} // this jump gives you a label with a real offset but you don't know the statement in question's offset.
我错过了什么?
答:
0赞
MeBigFatGuy
9/22/2023
#1
好的,想出办法了。
收集您收到的集合中的所有标签,然后当感兴趣的指令发生时,保存已访问标签的副本,同时仍收集原始集合中的标签。visitLabel
当您访问JMP指令时,如果该标签位于感兴趣指令时收集的访问标签集,您就知道这是一个循环。
评论
0赞
Peter Cordes
9/22/2023
如果 Java 编译器(或手写字节码)可以像 C 编译器在为实际 CPU 制作 asm/机器代码时所做的那样多样化,那么一些非循环代码的分支布局可能会破坏这种启发式方法。例如,godbolt.org/z/5czvz6Y44 显示 GCC 选择将主体放在函数的后面,因此当 为 true 时,它会跳到那里然后跳回较早的标签。 后面跟着一个 backwards ,但它不是循环的。如果我正确理解了你的答案,你的算法就会误报。也许 Java 编译器从不这样做?if
ret
if
call printf
jmp .L2
2赞
Holger
9/22/2023
@PeterCordes据我所知,Java 编译器不会这样做。另一方面,手工制作的字节码可以创建甚至人类都不确定它是否算作循环的构造。
0赞
Peter Cordes
9/22/2023
@Holger:那么在Java编译器输出中,向后分支总是循环分支?我想知道像这样更复杂的案例是否可以改变这一点,即使它们只是简单地列出。或者一个 lambda 在某个地方成为一个块,但只使用一次,因此该块可以通过跳转返回,而不需要返回地址?可能不是,编译器只会将其内联到唯一的调用站点中,而不是这样做。switch
2赞
Holger
9/23/2023
@PeterCordes当前编译器中没有这样的优化。lambda 表达式的主体总是被脱糖到方法中,因此即使存在针对仅本地使用的 lambda 表达式的优化,也可以直接实现为普通方法调用,而不是内联字节码。从理论上讲,可以优化 a 让标签向后指向,不知道这是否发生,以防万一或确实发生。但是,在这些情况下,向后分支仍指示存在环路。case …: continue;
switch
if … continue;
else continue;
评论