【问题标题】:Compiler Explorer Assembly Output for C, C++ and D (dlang) [closed]C、C++ 和 D(dlang)的编译器资源管理器程序集输出 [关闭]
【发布时间】:2021-05-27 08:40:13
【问题描述】:

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

  • 这些额外的行是什么?
  • 如何从生成中删除这些行?

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

【问题讨论】:

  • 当你打开godbolt.org链接时,square函数已经存在了。您只需要将语言从 C++ 更改为 C 或 D。
  • 默认输出未优化。比较那些未优化的代码是没有意义的
  • Godbolt 在手机上无法使用。请将问题中的代码和汇编输出作为代码格式的文本发布。
  • 我投票结束这个问题,因为在没有启用任何优化选项的情况下询问性能/基准测试是荒谬的。请编辑问题以在所有使用的语言中使用启用了优化器的代码...
  • D码默认是静态链接的。我相信这就是为什么你会看到这么长的输出。

标签: c++ assembly x86 d compiler-explorer


【解决方案1】:

这些是有问题的代码: 对于 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 程序或类似程序中,因此您可能无法/不应该删除它。

在您的第二个示例中,大部分代码是实现的输出库。 Using only the function defined 它实际上是 66 行长。虽然仍然比等效的 22 行 C++ 生成的程序集长,但它不是几千行。

编辑:

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

【讨论】:

  • 带有 glibc 的 Linux 上的 C 和 C++ 使用相同的 CRT 启动代码从 _start 获取到 main。这包括让_start 将main 的地址传递给__libc_start_main,以便它运行libc 启动代码,然后间接调用main。 (__libc_start_main 是 in libc,而不是在你的可执行文件本身,除非你静态链接)。
  • @Peter Cordes 哦,是的,对不起,我的错。我实际上是在谈论 _entry func 我只是愚蠢
  • 哪些系统使用_entry?` 在Linux(Godbolt 上的编译器目标)上,ELF 入口点通常称为_start。
猜你喜欢
  • 1970-01-01
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 2011-09-18
  • 2020-02-18
  • 2011-07-31
  • 1970-01-01
相关资源
最近更新 更多