考虑到 STG 生成自定义 ABI,Haskell 链接如何工作

How Haskell linking may work given that STG generates custom ABI

据我了解,从 STG 生成的代码使用非常自定义的 ABI,甚至具有自定义调用堆栈。

链接器是如何工作的? GHC 是否使用自定义链接器?

如果您 运行 ghc 使用 -v 标志来生成详细的日志输出,您会看到它调用 gcc 来执行最终的 link.当然,gcc 使用标准系统 ld linker,但有一些 GHC 认为有用的额外设置。

正如@arrowd 在评论中提到的,linker 并不真正关心调用约定。在大多数情况下,它只是修复对其他目标文件中符号的未定义引用,无论这些符号引用代码还是数据。

当一个 Haskell 模块被编译为本机代码时,它主要采用一堆数据结构(“闭包”)和以元数据为前缀的代码片段(“信息块”)的形式,并且数据和代码标有全局符号,可以被其他模块引用并由 linker 解析,与 linking C 程序时可能解析对数据结构或 C 函数的引用的方式相同.

作为一个简单的例子,相当愚蠢的模块:

module Foo where

foo :: (a -> b -> c) -> d -> a -> b -> c
foo f = const f

当使用 ghc -c -O0 -fforce-recomp -ddump-asm Foo.hs 编译时,基本上会为 foo 生成以下信息块和闭包(通过删除一些额外的汇编编译指示进行简化)。

;; info block, proceeded by a few quad words of metadata
.section .text
    .quad   4294967301
    .quad   0
    .long   14
    .long   GHC.Base.const_closure-(Foo.foo_info)+0
Foo.foo_info:
    movl $GHC.Base.const_closure,%ebx
    jmp stg_ap_p_fast
    .size Foo.foo_info, .-Foo.foo_info

;; closure    
.section .data
Foo.foo_closure:
    .quad   Foo.foo_info
    .quad   0

符号Foo.foo_infoFoo.foo_closure被模块导出,符号Base.const_closure被模型中的代码和数据引用,成为必须解析的未定义符号.

使用此 foo 函数的另一个调用模块通常会通过引用符号 Foo.foo_closure 来执行此操作。 linker 会在Foo 模块中解析调用模块对Foo.foo_closure 标签的引用,也会解析Foo 模块对标签GHC.Base.const_closure 在 GHC 基础包中。