JIT生成代碼反彙編

一、背景

我們知道,通過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
  ......

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章