haskell - variable - Comprender la salida de ensamblaje de GHC
open haskell (1)
Al compilar un archivo fuente de haskell usando la opción -S en GHC, el código de ensamblaje generado no es claro. No hay una distinción clara entre qué partes del código de ensamblaje pertenecen a qué partes del código de haskell. A diferencia de GCC, cada etiqueta se nombra de acuerdo con la función a la que corresponde.
¿Hay alguna convención en estos nombres producida por GHC? ¿Cómo puedo relacionar ciertas partes del código ensamblador generado con sus partes correspondientes en el código haskell?
Para declaraciones de nivel superior, no es demasiado difícil. Las definiciones locales pueden ser más difíciles de reconocer ya que sus nombres se mutilan y es probable que se incluyan.
Veamos qué sucede cuando compilamos este módulo simple.
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"
Puede ver que nuestra función Example.add
resultó en la generación de Example_add_closure
y Example_add_info
. La parte _closure
, como su nombre indica, tiene que ver con cierres. La parte _info
contiene las instrucciones reales de la función. En este caso, esto es simplemente un salto a la función GHC.Base.plusInt
.
Tenga en cuenta que el conjunto generado a partir del código Haskell se ve bastante diferente de lo que podría obtener de otros idiomas. Las convenciones de llamada son diferentes, y las cosas se pueden reordenar mucho.
En la mayoría de los casos, no quiere saltar directamente al montaje. Por lo general, es mucho más fácil de entender core , una versión simplificada de Haskell. (Más simple de compilar, no necesariamente para leer). Para llegar al núcleo, compile con la opción -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
Para obtener algunos buenos recursos sobre cómo leer el núcleo, vea esta pregunta .