首页 > 解决方案 > C、C++ 和 D (dlang) 的编译器资源管理器程序集输出

问题描述

在使用 Compiler Explorer ( https://godbolt.org/ ) 比较简单程序的汇编输出时,为什么 D 语言的汇编输出与 C 或 C++ 输出相比如此之长。简单的 square 函数输出对于 C、C++ 和 D 是相同的,但 D 输出有额外的行,当将鼠标悬停在源代码中的 square 函数上时,这些行不会突出显示。

假设我在 C++ 和 D 中都有https://godbolt.org/z/64EsWo5Ke模板函数,D 的 Intel asm 输出为 29309 行,而 C++ Intel asm 输出仅为 73 行。

标签: c++assemblyx86dcompiler-explorer

解决方案


这些是有问题的代码: 对于 D:

int example.square(int):
        push    rbp
        mov     rbp, rsp
        mov     dword ptr [rbp - 4], edi
        mov     eax, dword ptr [rbp - 4]
        imul    eax, dword ptr [rbp - 4]
        pop     rbp
        ret

ldc.register_dso:
        sub     rsp, 40
        mov     qword ptr [rsp + 8], 1
        lea     rax, [rip + ldc.dso_slot]
        mov     qword ptr [rsp + 16], rax
        lea     rax, [rip + __start___minfo]
        mov     qword ptr [rsp + 24], rax
        lea     rax, [rip + __stop___minfo]
        mov     qword ptr [rsp + 32], rax
        lea     rax, [rsp + 8]
        mov     rdi, rax
        call    _d_dso_registry@PLT
        add     rsp, 40
        ret

example.__ModuleInfo:
        .long   2147483652
        .long   0
        .asciz  "example"

example.__moduleRef:
        .quad   example.__ModuleInfo

ldc.dso_slot:
        .quad   0

C/C++:

square(int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, eax
        pop     rbp
        ret

如您所见,汇编中的实际实现非常相似(几乎相同)。程序构造堆栈帧:

        push    rbp
        mov     rbp, rsp

获取参数并将其与自身相乘,并将其保留在返回值(eax寄存器)中:

        mov     dword ptr [rbp - 4], edi
        mov     eax, dword ptr [rbp - 4]
        imul    eax, dword ptr [rbp - 4]

在 D 和

        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, eax

在 C++/C 中,然后解构堆栈帧并返回:

        pop     rbp
        ret

现在我不声称知道 D 编译器在做什么,但我假设其余代码是为了让这段编译后的代码可以与其他 D 代码很好地协同工作。基本上是元数据和其他有趣的东西。我假设这是因为我们的函数在任何地方都没有使用任何定义的符号,其他函数也没有调用正方形。因此,此代码可能会包含在其他 D 程序或类似程序中,因此您可能无法/不应该删除它。

在您的第二个示例中,大部分代码是实现的输出库。仅使用定义的函数实际上是 66 行长。虽然仍然比等效的 22 行 C++ 生成的程序集长,但它不是几千行。

编辑:

正如我在评论中解释的那样,建议使用 Cutter 或 Ghidra 之类的工具分析输出二进制文件,这可以让您更全面地了解二进制文件中实际生成的内容,因为我可以告诉您,即使在“较短”的 C++ 代码中,您会发现很多函数调用,例如_entry在进入 main 之前。


推荐阅读