[公告] 字节码指令与本地汇编指令的对应关系

德星邸 2011-09-22
不知道Java类的字节码指令是如何对应本地的汇编代码指令的呢
RednaxelaFX 2011-09-23
不是一定有直接的对应关系的。字节码可以通过编译的方式以一大块为单位(称为“编译单元”)翻译为机器码并缓存起来,后面执行这个已经翻译好的代码;也可以以解释的方式一条条字节码指令跑固定的代码。

编译的话,编译单元有可能是方法,也有可能是“trace”,或者是basic block/dynamic basic block之类的,可以有许多选择。

如果是个优化的编译器,在优化的过程中原本的字节码就不一定能完整的跟最终生成的机器码一块块对应起来了。

==============================================================

即便是设定了固定对应关系也有许多不同的取舍方式。举几个例子给你看。

编译器:

如果一个编译器里输入的字节码与生成的机器码之间有固定的、直接的对应关系的话,这种编译器就是所谓的“基于模板的编译器”(template-based compiler)或者就叫“模板编译器”。

基于模板的编译器是最简单的实现编译器的方式了。也有把它叫做code-copying compiler的。像是这篇论文里的用词。

通过模板方式实现基准编译器的JVM有好一些,特别是早期的简易JIT编译器。就不看古董了,弄几个稍微新一些的来看,例如:
·Harmony的DRLVM里的Jitrino.JET,代码:这个目录里cg开头的那些文件,也就是CodeGen的实现。关于Jitrino.JET的Compiler与CodeGen的关系,参考jet.cpp里的注释。
·Jikes RVM里的BaselineCompiler,其x86上的实现代码:BaselineCompilerImpl
·Maxine VM里的T1X,这个实现有点特别,代码:T1XTemplateSource


解释器:

也有基于模板的解释器实现。Oracle/Sun JDK里的HotSpot VM里默认用的解释器就是这样的一种实现。可以以下面这个文件为入口去看x86-64上的实现:
http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/cpu/x86/vm/templateTable_x86_64.cpp
例如说aconst_null字节码指令对应的用C++写的模板就是:
void TemplateTable::aconst_null() {
  transition(vtos, atos);
  __ xorl(rax, rax);
}

实际出来的代码用汇编来表示的话会是这种样子:
  0x00007f9df90abda0: push   %rax
  0x00007f9df90abda1: jmpq   0x00007f9df90abdd0
  0x00007f9df90abda6: sub    $0x8,%rsp
  0x00007f9df90abdaa: movss  %xmm0,(%rsp)
  0x00007f9df90abdaf: jmpq   0x00007f9df90abdd0
  0x00007f9df90abdb4: sub    $0x10,%rsp
  0x00007f9df90abdb8: movsd  %xmm0,(%rsp)
  0x00007f9df90abdbd: jmpq   0x00007f9df90abdd0
  0x00007f9df90abdc2: sub    $0x10,%rsp
  0x00007f9df90abdc6: mov    %rax,(%rsp)
  0x00007f9df90abdca: jmpq   0x00007f9df90abdd0
  0x00007f9df90abdcf: push   %rax
  0x00007f9df90abdd0: xor    %eax,%eax      ;; 模板里的xorl(rax, rax)就是这句
  0x00007f9df90abdd2: movzbl 0x1(%r13),%ebx
  0x00007f9df90abdd7: inc    %r13
  0x00007f9df90abdda: mov    $0x7f9dfdd93220,%r10
  0x00007f9df90abde4: jmpq   *(%r10,%rbx,8)

这个模板的构成方式可以参考之前的一个PPT里讲到解释器的部分。

说来Google Android里的Dalvik VM(虽然不是JVM)里的解释器也是基于模板的。那个是直接用汇编写的模板。

==============================================================

基于模板的实现比较容易出现安全漏洞。ESUG 2009上有个讲座提到了Smalltalk虚拟机里的JIT编译器的安全问题

我以前也在HotSpot VM的解释器上试过shellcode,也成功了。参考这里:https://gist.github.com/888122
hellhell 2011-09-23
R大你调试hotspot时使用gdb么?感觉调试汇编很难啊,因为你拿到的指针很难判断是什么类型,顶多根据markOop判断出来是一个oop,markword后面是klass指针,你怎么判断出这个klass指针具体是代表什么java类型?
hellhell 2011-09-23
比如一个methodOop,以前还有个name字段,还可以人肉展开,7里面需要到constantPool里去找,大大增加了麻烦度,R大平时debug时是怎么解决这个问题的?
woosheep 2011-09-26
hotspot记得是用swtich/case解析字节码
hellhell 2011-09-26
woosheep 写道
hotspot记得是用swtich/case解析字节码

就算是用HotSpot VM里的“zero”解释器,也不是用switch/case方式实现的
Global site tag (gtag.js) - Google Analytics