这些是有问题的代码: 对于 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 之前。