解构 C++ 符号的歧义

Posted

技术标签:

【中文标题】解构 C++ 符号的歧义【英文标题】:Ambiguity of de-mangled C++ symbols 【发布时间】:2018-04-13 20:47:55 【问题描述】:
_ZNSaIwEC1Ev
_ZNSaIwEC2Ev

这两个 C++ 符号不同,但被分解(使用 C++filt 或类似实用程序)成相同的形式:

std::allocator<wchar_t>::allocator()
std::allocator<wchar_t>::allocator()

为什么会这样?会不会是 demangler 的缺陷还是其他什么?

【问题讨论】:

重整函数的逆函数是单射的重要吗?我只看到 mangling 函数是单射的有多重要。 【参考方案1】:

g++ 使用Itanium ABI 指定的名称修改方案(和其他实现细节)。

在mangling of constructors and destructors 部分,我们看到:

<ctor-dtor-name> ::= C1 # complete object constructor
                 ::= C2 # base object constructor
                 ::= C3 # complete object allocating constructor
                 ::= D0 # deleting destructor
                 ::= D1 # complete object destructor
                 ::= D2 # base object destructor
包括C1在内的“完整对象构造函数”是初始化直接使用的普通构造函数。 派生类构造函数使用包括C2 的“基对象构造函数”来初始化其基类子对象。当涉及到虚拟继承时,这可能与“完整”构造函数不同,因为只有完整的构造函数会初始化虚拟基,而基构造函数会假设它们的虚拟基已经被初始化。 “完整的对象分配构造函数”包括C3 大概包括对operator new 的调用。但据我所知,g++ 从未真正使用过这个。 “删除析构函数”包括D0 以调用适当的标量operator delete 结束。这对于绑定到虚拟析构函数是必要的,因为正确的 operator delete 可能是基类一无所知的静态类成员。 包括D1 在内的“完整对象析构函数”与C1 构造函数的相反,包括对虚拟基类析构函数的调用。 包括D2 在内的“基对象析构函数”与C2 构造函数的相反,省略了对虚拟基类析构函数的调用。

因此,您询问的错位名称中的 C1C2 部分暗示了对 C++ 系统很重要且必须单独正确链接的信息。但是这些信息很难在伪代码声明中简要解释,因此解构函数只是对两个符号进行了相同的描述。

虽然由于std::allocator&lt;T&gt; 通常没有任何虚拟基类,但很可能这两个符号实际上指向相同的代码地址,但 g++ 只是提供了两个链接器符号以保持一致性。

【讨论】:

在我的例子中,它们并不指向同一个地址,但代码是相同的。

以上是关于解构 C++ 符号的歧义的主要内容,如果未能解决你的问题,请参考以下文章

JVM符号引用和直接引用

Java虚拟机 - 符号引用和直接引用理解

java -- JVM的符号引用和直接引用

C++ 隐式转换(有符号 + 无符号)

打印定义给定符号的库的名称

无法解析的外部符号 C++