我对为什么我们使用名称重整的理解是汇编器和链接器只能处理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 定义了 5 种不同的方法来修改同一构造函数的名称,具体取决于编译器生成的构造函数变体。 同样,有三种不同的方法来破坏给定析构函数的名称。 符号_ZN3fooC1Ev
和_ZN3fooC2Ev
都像foo::foo()
一样解散,并且都可以存在于同一个程序中。
当然,你可以发明新的类似C++的语法来表示这些东西,但你只是发明了更冗长的符号处理方式。
最后,也许C++编译器以这种方式修改名称的最重要原因是他们可以使用各种工具。 虽然它今天不太常见,但 GNU C++编译器可以与 GAS 以外的汇编器一起使用。