2011-07-24 22 views
29

Podczas kompilowania pliku źródłowego haskell za pomocą opcji -S w GHC wygenerowany kod zespołu jest niewyraźny. Nie ma wyraźnego rozróżnienia między częściami kodu zespołu, które należą do części kodu haskell. W przeciwieństwie do GCC każda etykieta została nazwana zgodnie z funkcją, której odpowiada.Opis wyjścia zespołu GHC

Czy istnieje pewna konwencja w tych nazwach stworzona przez GHC? Jak mogę powiązać określone części w wygenerowanym kodzie zespołu z odpowiednimi częściami w kodzie haskell?

Odpowiedz

26

W przypadku deklaracji najwyższego poziomu nie jest to zbyt trudne. Lokalne definicje mogą być trudniejsze do rozpoznania, ponieważ ich nazwy zostają zniekształcone i prawdopodobnie zostaną przedstawione.

Zobaczmy, co się stanie, gdy skompilujemy ten prosty moduł.

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" 

Widać, że nasza funkcja Example.add spowodowało wygenerowanie Example_add_closure i Example_add_info. Część _closure, jak sama nazwa wskazuje, ma związek z zamknięciami. Część _info zawiera rzeczywiste instrukcje funkcji. W tym przypadku jest to po prostu skok do wbudowanej funkcji GHC.Base.plusInt.

Należy zauważyć, że zestaw generowany z kodu Haskella wygląda zupełnie inaczej niż w innych językach. Konwencje wywoływania są różne i wiele rzeczy może się zmienić.

W większości przypadków nie należy przeskakiwać bezpośrednio do montażu. Zwykle znacznie łatwiej jest zrozumieć rdzeń, uproszczoną wersję Haskella. (Prostsze do kompilacji, niekoniecznie do czytania). Aby dostać się do rdzenia, skompiluj z opcją -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 

Aby uzyskać informacje na temat dobrego odczytu rdzenia, zobacz this question.