c++ - 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 行。
解决方案
这些是有问题的代码: 对于 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 之前。
推荐阅读
- php - 如何确保对我的服务器的请求的来源是合法的?
- javascript - 如何在 GitHub Pages 中使用基本的 Google Sheets javascript 脚本?
- android-studio - Android 启动,然后进入黑屏。亚行外壳工程
- java - 在 Java 中使用 PDFBox 创建嵌套列表
- node.js - 无法读取视图引擎节点 js 中未定义的属性“名字”
- go - Go vs C++ 中的抽象基类设计
- ruby - 当我不调用 mk_dir 时,文件存在 @ dir_s_mkdir
- vaadin8 - Vaadin 8 Treegrid 总是通过使用 AbstractBackEndHierarchicalDataProvider 进行延迟加载来获取所有行
- javascript - 如何在 Two.js 中为形状添加事件?
- matlab - 在没有内置 MATLAB 函数的情况下构造具有自然边界条件的三次样条