1

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

但这似乎是我们工具的一个相对微不足道的限制。我们不能或不编写汇编器和链接器是否有任何充分的理由,其中的内容如下:

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

可以吗?

4

1 回答 1

4

您实际上可以将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都 demangle asfoo::foo()和 都可以存在于同一个程序中。

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

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

于 2020-06-26T18:53:13.743 回答