为什么 JSR/RET 不推荐使用 Java 字节码?
有谁知道为什么 JSR/RET 字节码对在 Java 6 中被弃用?
我在网上找到的唯一有意义的解释是,它们使运行时的代码分析变得更加困难且执行速度更慢。有谁知道另一个原因吗?
Does anyone know why the JSR/RET bytecode pair is deprecated in Java 6?
The only meaningful explanation I found on the net was that they made code analysis by the runtime harder and slower to perform. Does anyone know another reason?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
JSR 和 RET 使字节码验证变得更加困难,因为放宽了一些正常的字节码约束(例如在进入 JSR 时具有一致的堆栈形状)。优点非常小(在某些情况下可能会稍小一些),并且验证器处理奇怪的 JSR/RET 模式(以及潜在的安全漏洞,以及完整验证的相关运行时成本)的持续困难使其成为一个无用的功能继续拥有。
堆栈映射和由于数据而启用的轻量级验证器在类加载过程中取得了巨大的性能优势,而且不牺牲安全性。
JSR and RET make bytecode verification a lot more difficult than it might otherwise be due to the relaxation of some normal bytecode constraints (such as having a consistent stack shape on entry to a JSR). The upside is very minor (potentially slightly smaller methods in some cases) and the continuing difficulties in the verifier dealing with odd JSR/RET patterns (and potential security vulnerabilities, and the associated runtime cost of full verification) make it a non-useful feature to continue having.
Stack maps and the lighter-weight verifier that is enabled as a result of the data are a big performance win during class loading for no sacrifice in safety.
使用它们来混淆字节码的人解释了原因:
最后一句仅与混淆器相关(例如基于
soot
的 JBCO),它甚至不放置ret
而是pop
返回地址,模拟 goto。大约 15 年后,这对于某些“现代”反编译器仍然足够有效:撇开这个(相对简单的)技巧不谈,引文的第一部分说(即使)如果“按最初设计的”使用
jsr
s导致(数据流)分析速度减慢。字节码验证器是一个数据流分析器,请参阅 Leroy 进行深入讨论——我可能应该在命名之前停下来 抽象解释在这里,尽管这也[概念上]涉及字节码验证......但是,在 Leroy 中更详细地讲,
jsr
引入了这种复杂性:相关引用如下:
后者的结论 (2003) 论文:
Coglio 的后续 (2004) 论文 指出(第 666 页)大多数 Java 字节码验证器实现都违反了 JVM 规范,并拒绝了一些涉及子例程的有效(规范方面)程序。
勒罗伊的另一个花絮/批评:
Coglio 2004 年的论文还指出,CLR 在其 VM 操作码级别有一个内置的
endfinally
,这避免了 jsr/ret 的一些问题。看起来这是因为您 不能通过其他指令自由地跳入或跳出 CLR 中的此类块,而您可以跳入/跳出没有特定/强制边界的“子例程”在 JVM 中也是如此,这使事情变得复杂。The people who use them to obfuscate bytecode explain why:
The last sentence is only relevant for obfuscators (like the
soot
-based JBCO) which don't even put aret
butpop
the return address, emulating a goto. That's still effective enough ~15 years later against some 'modern' decompilers:That (relatively simple) trick aside, the first part of the quote says that (even) if used 'as originally designed'
jsr
s cause (dataflow) analysis slowdowns. A bytecode verifier is a dataflow analyzer, see Leroy for an in-depth discussion--I should probably stop before I namedrop abstract interpretation here, although that's also [conceptually] involved in bytecode verification...But, in more detail in Leroy, there's this complication that
jsr
introduced:The relevant citations there being:
The conclusions of the latter (2003) paper:
A subsequent (2004) paper by Coglio notes (on p. 666) that most Java bytecode verifier implementations violated the JVM spec and rejected some valid (spec-wise) programs involving subroutines.
Another titbit/criticism from Leroy:
Coglio's 2004 paper also noted that CLR has a built-in
endfinally
at their VM opcode level, which avoids some issues with jsr/ret. It looks like that's because you can't freely jump in or out of such blocks in CLR by means of other instructions, while you can goto in/out of a 'subroutine', which has no specific/enforced boundaries as such in the JVM, which complicated matters.