为什么我们不编写可以处理 C++ 标识符的汇编器和链接器?

Why don't we write assemblers and linkers that can handle C++ identifiers?

我对我们为什么使用名称修改的理解是汇编器和链接器只能处理 C 标识符。 “int foo::bar::baz<spam::eggs>(const MoreSpam&)”不能被任何现有的汇编器用作标签,并且现有的链接器不会将其识别为有效的函数签名,因此它变成类似“_ZN3foo3bar3bazIN4spam4eggsEEEiRK8MoreSpam”的东西,即(或多或少)一个有效的 C 标识符。

但这似乎是我们工具的一个相对微不足道的限制。有什么好的理由说明我们不能或不编写这样的汇编器和链接器:

int foo::bar::baz<spam::eggs>(MoreSpam const&):
    ; opcodes go here
    ret

可以吗?

您实际上可以使用 int foo::bar::baz<spam::eggs>(const MoreSpam&) 作为 GNU 汇编程序的标识符,您只需要将名称放在引号中:

"int foo::bar::baz<spam::eggs>(MoreSpam const&)":
        ret
$ as -o test.o test.s
$ nm test.o
0000000000000000 t int foo::bar::baz<spam::eggs>(MoreSpam const&)
$ ld test.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ nm a.out
0000000000402000 T __bss_start
0000000000402000 T _edata
0000000000402000 T _end
0000000000401000 t int foo::bar::baz<spam::eggs>(MoreSpam const&)
                 U _start

一个问题是,除了在很多上下文中处理带有空格和符号的符号是一种痛苦之外,并非所有 C++ 损坏的标识符都可以明确表示为 C++ 源代码片段。同一个 C++“符号”可以有多个错位表示,一些错位符号没有 C++ 表示。

例如,GNU C++ 编译器使用的 Itanium C++ ABI defines 5 different ways of mangling the name of the same constructor 取决于编译器生成的构造函数的变体。类似地,有三种不同的方法来破坏给定析构函数的名称。符号 _ZN3fooC1Ev_ZN3fooC2Ev 都分解为 foo::foo() 并且都可以存在于同一个程序中。

当然你可以发明新的类似 C++ 的语法来表示这些东西,但你只是在发明更冗长的符号处理方式。

最后,也许 C++ 编译器以这种方式破坏名称的最重要原因是它们可以使用各种工具。虽然现在不太常见,但 GNU C++ 编译器可以与 GAS 以外的汇编程序一起使用。