使用GHC中的-S選項編譯haskell源文件時,生成的彙編代碼不清晰。彙編代碼的哪些部分屬於haskell代碼的哪些部分之間沒有明確的區別。與GCC不同,每個標籤都是根據其對應的功能命名的。瞭解GHC彙編輸出
GHC生成的這些名稱是否存在某種約定?我如何將生成的彙編代碼中的某些部分與haskell代碼中的相應部分相關聯?
使用GHC中的-S選項編譯haskell源文件時,生成的彙編代碼不清晰。彙編代碼的哪些部分屬於haskell代碼的哪些部分之間沒有明確的區別。與GCC不同,每個標籤都是根據其對應的功能命名的。瞭解GHC彙編輸出
GHC生成的這些名稱是否存在某種約定?我如何將生成的彙編代碼中的某些部分與haskell代碼中的相應部分相關聯?
對於頂級聲明,這並不難。局部定義可能更難以識別,因爲他們的名字會被破壞,並且可能會被內聯。我們來看看編譯這個簡單模塊時會發生什麼。
module Example where
add :: Int -> Int -> Int
add x y = x + y
.data .align 8 .globl Example_add_closure .type Example_add_closure, @object Example_add_closure: .quad Example_add_info .text .align 8 .quad 8589934604 .quad 0 .quad 15 .globl Example_add_info .type Example_add_info, @object Example_add_info: .LckX: jmp base_GHCziBase_plusInt_info
.data
.align 8
_module_registered:
.quad 0
.text
.align 8
.globl __stginit_Example_
.type __stginit_Example_, @object
__stginit_Example_:
.Lcl7:
cmpq $0,_module_registered
jne .Lcl8
.Lcl9:
movq $1,_module_registered
addq $-8,%rbp
movq $__stginit_base_Prelude_,(%rbp)
.Lcl8:
addq $8,%rbp
jmp *-8(%rbp)
.text
.align 8
.globl __stginit_Example
.type __stginit_Example, @object
__stginit_Example:
.Lcld:
jmp __stginit_Example_
.section .note.GNU-stack,"",@progbits
.ident "GHC 7.0.2"
你可以看到,我們的功能Example.add
導致的Example_add_closure
和Example_add_info
產生。顧名思義,_closure
部分與閉包有關。 _info
部分包含該函數的實際說明。在這種情況下,這只是跳轉到內置功能GHC.Base.plusInt
。
請注意,從Haskell代碼生成的程序集看起來與您可能從其他語言獲得的程序完全不同。調用約定是不同的,事情可以重新排序。
在大多數情況下,您不想直接跳到裝配。理解核心是Haskell的簡化版本,通常要容易得多。 (更容易編譯,不一定閱讀)。要了解核心,請使用-ddump-simpl
選項進行編譯。
Example.add :: GHC.Types.Int -> GHC.Types.Int -> GHC.Types.Int
[GblId, Arity=2]
Example.add =
\ (x_abt :: GHC.Types.Int) (y_abu :: GHC.Types.Int) ->
GHC.Num.+ @ GHC.Types.Int GHC.Num.$fNumInt x_abt y_abu
對於如何讀取核心的一些很好的資源,請參閱this question。