JIT生成代码反汇编(HSDIS)

一、背景

我们知道,通过javap命令可以查看字节码信息,我们通过字节码可以知道对于一个程序,虚拟机做了些什么事情。但是各大虚拟机厂商对其的实现细节可能会大不相同,字节码只能从语义上解释程序的执行。如果我们要分析程序在宿主环境中到底是如何运行的,字节码则不能给我们提供足够详细的信息了,这个时候我们就需要站在汇编的角度考虑问题。

二、HSDIS

 HSDIS是sun推荐的HotSpot虚拟机JIT编译代码的反汇编插件,它包含在HotSpot虚拟机的源码中,但没有提供编译后的程序。HotSpot的-XX:PrintAssemBly指令可以调用它来把本地代码还原为汇编代码输出,同时还生成了一些注释。由于编译比较麻烦,这里就直接贴出可用于windows64位的下载地址:

链接: https://pan.baidu.com/s/1POT2B96z2FFu3qpfbb7pBw

提取码: 2xe9

下载该文件后放到JDK_HOME/jre/bin/server或JDK_HOME/jre/bin/client下即可。

三、实践

首先我们定义一个类(代码本身没有什么实际的意义):

public class Test {
   public static void print(int n) {
        for (int i = 0; i < n; i++) {
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        Test.print(10);
    }
}

我们首先需要使用javac编译源码文件:

javac Test.java

然后使用HSDIS插件进行反汇编:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=b.log -Xcomp -XX:CompileCommand=compileonly,Test.print Test

其中的参数含义如下:

-XX:+UnlockDiagnosticVMOptions:Product版的HotSpot则需要加上此参数,如果是Debug或FastDebug版的HotSpot,则可以忽略它

-XX:+PrintAssembly:表示输出反汇编内容

-XX:+LogCompilation:表示生成日志文件

-XX:LogFile:日志文件路径(生成日志文件之后,可以用其它工具做详细分析,比如JITWatch)

-Xcomp:让虚拟机以编译模式执行代码,使用它我们可以不必做预热操作就能触发JIT编译(如果该参数在实际使用的虚拟机中已经被移除,那么还是需要做预热才能触发JIT编译,简单做个循环预热就可以了)

-XX:CompileCommand:用于指定compile指令。我们配置compileonly,表示只编译Test#print方法

对应的输出结果如下(没有贴完哈),为AT&T风格,%开头表示寄存器,$开头表示立即数:

Decoding compiled method 0x0000000002fb1fd0:
Code:
[Disassembling for mach='i386:x86-64']
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x00000000195402b8} 'print' '(I)V' in 'Test'
  # parm0:    rdx       = int
  #           [sp+0x40]  (sp of caller)
  0x0000000002fb2160: mov    %eax,-0x6000(%rsp)
  0x0000000002fb2167: push   %rbp
  0x0000000002fb2168: sub    $0x30,%rsp
  0x0000000002fb216c: mov    %edx,0x24(%rsp)
  0x0000000002fb2170: movabs $0x19540488,%r8    ;   {metadata(method data for {method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb217a: mov    0xdc(%r8),%esi
  0x0000000002fb2181: add    $0x8,%esi
  0x0000000002fb2184: mov    %esi,0xdc(%r8)
  0x0000000002fb218b: movabs $0x195402b0,%r8    ;   {metadata({method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb2195: and    $0x0,%esi
  0x0000000002fb2198: cmp    $0x0,%esi
  0x0000000002fb219b: je     0x0000000002fb2312  ;*iconst_0
                                                ; - Test::print@0 (line 3)

  0x0000000002fb21a1: mov    $0x0,%esi
  0x0000000002fb21a6: jmpq   0x0000000002fb22ce  ;*iload_1
                                                ; - Test::print@2 (line 3)

  0x0000000002fb21ab: nopl   0x0(%rax,%rax,1)
  0x0000000002fb21b0: jmpq   0x0000000002fb2386  ;   {no_reloc}
  0x0000000002fb21b5: add    %al,(%rax)
  0x0000000002fb21b7: add    %al,(%rax)
  0x0000000002fb21b9: add    %ah,0xf(%rsi)
  0x0000000002fb21bc: (bad)
  0x0000000002fb21bd: add    %r8b,(%rax)
  0x0000000002fb21c0: jmpq   0x0000000002fb23a1  ; implicit exception: dispatches to 0x0000000002fb2390
  0x0000000002fb21c5: nop
  0x0000000002fb21c6: nop
  0x0000000002fb21c7: shl    $0x3,%rdi          ;*getstatic out
                                                ; - Test::print@7 (line 4)

  0x0000000002fb21cb: cmp    (%rdi),%rax        ; implicit exception: dispatches to 0x0000000002fb23ab
  0x0000000002fb21ce: mov    %rdi,%r8
  0x0000000002fb21d1: movabs $0x19540488,%rbx   ;   {metadata(method data for {method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb21db: mov    0x8(%r8),%r8d
  0x0000000002fb21df: shl    $0x3,%r8
  0x0000000002fb21e3: cmp    0x130(%rbx),%r8
  0x0000000002fb21ea: jne    0x0000000002fb21f9
  0x0000000002fb21ec: addq   $0x1,0x138(%rbx)
  0x0000000002fb21f4: jmpq   0x0000000002fb225f
  0x0000000002fb21f9: cmp    0x140(%rbx),%r8
  0x0000000002fb2200: jne    0x0000000002fb220f
  0x0000000002fb2202: addq   $0x1,0x148(%rbx)
  0x0000000002fb220a: jmpq   0x0000000002fb225f
  0x0000000002fb220f: cmpq   $0x0,0x130(%rbx)
  0x0000000002fb221a: jne    0x0000000002fb2233
  0x0000000002fb221c: mov    %r8,0x130(%rbx)
  0x0000000002fb2223: movq   $0x1,0x138(%rbx)
  0x0000000002fb222e: jmpq   0x0000000002fb225f
  0x0000000002fb2233: cmpq   $0x0,0x140(%rbx)
  0x0000000002fb223e: jne    0x0000000002fb2257
  0x0000000002fb2240: mov    %r8,0x140(%rbx)
  0x0000000002fb2247: movq   $0x1,0x148(%rbx)
  0x0000000002fb2252: jmpq   0x0000000002fb225f
  0x0000000002fb2257: addq   $0x1,0x128(%rbx)
  0x0000000002fb225f: mov    %rsi,%r8
  0x0000000002fb2262: mov    %rdi,%rdx          ;*invokevirtual println
                                                ; - Test::print@11 (line 4)

  0x0000000002fb2265: mov    %esi,0x20(%rsp)
  0x0000000002fb2269: nop
  0x0000000002fb226a: nop
  0x0000000002fb226b: nop
  0x0000000002fb226c: nop
  0x0000000002fb226d: movabs $0xffffffffffffffff,%rax
  0x0000000002fb2277: callq  0x0000000002ef63e0  ; OopMap{off=284}
                                                ;*invokevirtual println
                                                ; - Test::print@11 (line 4)
                                                ;   {virtual_call}
  0x0000000002fb227c: mov    0x20(%rsp),%esi
  0x0000000002fb2280: inc    %esi
  0x0000000002fb2282: movabs $0x19540488,%rdi   ;   {metadata(method data for {method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb228c: mov    0xe0(%rdi),%ebx
  0x0000000002fb2292: add    $0x8,%ebx
  0x0000000002fb2295: mov    %ebx,0xe0(%rdi)
  0x0000000002fb229b: movabs $0x195402b0,%rdi   ;   {metadata({method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb22a5: and    $0xfff8,%ebx
  0x0000000002fb22ab: cmp    $0x0,%ebx
  0x0000000002fb22ae: je     0x0000000002fb23b0  ; OopMap{off=340}
                                                ;*goto
                                                ; - Test::print@17 (line 3)

  0x0000000002fb22b4: test   %eax,-0x1f821ba(%rip)        # 0x0000000001030100
                                                ;   {poll}
  0x0000000002fb22ba: movabs $0x19540488,%rdi   ;   {metadata(method data for {method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb22c4: incl   0x158(%rdi)        ;*goto
                                                ; - Test::print@17 (line 3)

  0x0000000002fb22ca: mov    0x24(%rsp),%edx
  0x0000000002fb22ce: cmp    %edx,%esi
  0x0000000002fb22d0: movabs $0x19540488,%r8    ;   {metadata(method data for {method} {0x00000000195402b8} 'print' '(I)V' in 'Test')}
  0x0000000002fb22da: movabs $0x108,%rdi
  0x0000000002fb22e4: jge    0x0000000002fb22f4
  0x0000000002fb22ea: movabs $0x118,%rdi
  0x0000000002fb22f4: mov    (%r8,%rdi,1),%rbx
  0x0000000002fb22f8: lea    0x1(%rbx),%rbx
  0x0000000002fb22fc: mov    %rbx,(%r8,%rdi,1)
  0x0000000002fb2300: jl     0x0000000002fb21b0  ;*if_icmpge
                                                ; - Test::print@4 (line 3)

  0x0000000002fb2306: add    $0x30,%rsp
  0x0000000002fb230a: pop    %rbp
  0x0000000002fb230b: test   %eax,-0x1f82211(%rip)        # 0x0000000001030100
                                                ;   {poll_return}
  0x0000000002fb2311: retq
  0x0000000002fb2312: mov    %r8,0x8(%rsp)
  0x0000000002fb2317: movq   $0xffffffffffffffff,(%rsp)
  0x0000000002fb231f: callq  0x0000000002fb0120  ; OopMap{off=452}
                                                ;*synchronization entry
                                                ; - Test::print@-1 (line 3)
                                                ;   {runtime_call}
  0x0000000002fb2324: jmpq   0x0000000002fb21a1
  0x0000000002fb2329: movabs $0x0,%r8           ;   {oop(NULL)}
  0x0000000002fb2333: push   %rax
  0x0000000002fb2334: push   %rbx
  0x0000000002fb2335: mov    0x48(%r8),%rbx
  0x0000000002fb2339: push   %rdi
  0x0000000002fb233a: push   %rsi
  0x0000000002fb233b: push   %rdx
  0x0000000002fb233c: push   %rcx
  0x0000000002fb233d: push   %r8
  0x0000000002fb233f: push   %r9
  0x0000000002fb2341: push   %r10
  0x0000000002fb2343: mov    %rsp,%r10
  0x0000000002fb2346: and    $0xfffffffffffffff0,%rsp
  0x0000000002fb234a: push   %r10
  0x0000000002fb234c: push   %r11
  0x0000000002fb234e: mov    $0x7,%ecx
  0x0000000002fb2353: movabs $0x7ff9f36a4c90,%r10  ;   {runtime_call}
  0x0000000002fb235d: callq  *%r10
  0x0000000002fb2360: pop    %r11
  0x0000000002fb2362: pop    %rsp
  0x0000000002fb2363: pop    %r10
  0x0000000002fb2365: pop    %r9
  0x0000000002fb2367: pop    %r8
  0x0000000002fb2369: pop    %rcx
  0x0000000002fb236a: pop    %rdx
  0x0000000002fb236b: pop    %rsi
  0x0000000002fb236c: pop    %rdi
  0x0000000002fb236d: cmp    0x118(%rbx),%rax
  0x0000000002fb2374: pop    %rbx
  0x0000000002fb2375: pop    %rax
  0x0000000002fb2376: jne    0x0000000002fb2386
  0x0000000002fb237c: jmpq   0x0000000002fb21ba
  0x0000000002fb2381: mov    $0xa535d00,%eax
  0x0000000002fb2386: callq  0x0000000002faf4a0  ; OopMap{off=555}
                                                ;*getstatic out
                                                ; - Test::print@7 (line 4)
                                                ;   {runtime_call}
  0x0000000002fb238b: jmpq   0x0000000002fb21b0
  0x0000000002fb2390: callq  0x0000000002fab8c0  ; OopMap{r8=Oop off=565}
                                                ;*getstatic out
                                                ; - Test::print@7 (line 4)
                                                ;   {runtime_call}
  0x0000000002fb2395: mov    0x0(%r8),%edi
  0x0000000002fb239c: mov    $0x7050c00,%eax
  0x0000000002fb23a1: callq  0x0000000002faec20  ; OopMap{r8=Oop off=582}
                                                ;*getstatic out
                                                ; - Test::print@7 (line 4)
                                                ;   {runtime_call}
  0x0000000002fb23a6: jmpq   0x0000000002fb21c0
  0x0000000002fb23ab: callq  0x0000000002fab8c0  ; OopMap{rdi=Oop off=592}
                                                ;*invokevirtual println
                                                ; - Test::print@11 (line 4)
                                                ;   {runtime_call}
  0x0000000002fb23b0: mov    %rdi,0x8(%rsp)
  0x0000000002fb23b5: movq   $0x11,(%rsp)
  0x0000000002fb23bd: callq  0x0000000002fb0120  ; OopMap{off=610}
                                                ;*goto
                                                ; - Test::print@17 (line 3)
                                                ;   {runtime_call}
  0x0000000002fb23c2: jmpq   0x0000000002fb22b4
  0x0000000002fb23c7: nop
  0x0000000002fb23c8: nop
  0x0000000002fb23c9: mov    0x2a8(%r15),%rax
  0x0000000002fb23d0: movabs $0x0,%r10
  0x0000000002fb23da: mov    %r10,0x2a8(%r15)
  0x0000000002fb23e1: movabs $0x0,%r10
  0x0000000002fb23eb: mov    %r10,0x2b0(%r15)
  0x0000000002fb23f2: add    $0x30,%rsp
  0x0000000002fb23f6: pop    %rbp
  0x0000000002fb23f7: jmpq   0x0000000002f1e2e0  ;   {runtime_call}
  0x0000000002fb23fc: hlt
  0x0000000002fb23fd: hlt
  ......

猜你喜欢

转载自blog.csdn.net/huangzhilin2015/article/details/89766497