首先,我们可以查看可用信息,并使用它开始搜索。当您使用 Linux 时,它很可能是 GCC 或 Clang 重整符号,这为我们提供了一个很好的起点:我们可以查找有关 GNU 重整方案的信息。
接下来,寻找符号中的模式。有多个一数多字母字符串,其中数字为字符串中字母的总数;这可能表明这些是名称。
考虑到这一点,我们可以将符号ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7 分解为:
Z
N
5Gnome
5Glade
3Xml
6create
E
R
K
S
s
R
K
N
4Glib
7ustring
E
S
7
现在,根据PDF "Calling Conventions" (pg.38) 中描述的 GNU3-4 修改方案,名称被编码为:
<public name> ::= _Z <qualified name>
<qualified name> ::= N [<simple name>]<sup>∞</sup><sub>2</sub> E
There are a minimum of 2 "simple name" symbols.
<simple name> ::= <name length> <name>
"Name length" is a decimal number indicating the length of "name".
Nested names are listed inwards, with the leftmost one being the outermost.
我们可以用它来拼凑一个部分符号,以及它的含义:
Symbol: _ZN5Gnome5Glade3Xml6createE
Means : The symbol's qualified name is "Gnome::Glade::Xml::create".
Note : At least one underscore appears to have been dropped by the error message.
考虑到它后面的垃圾和名称本身,这是一个函数符号。因此,考虑到这一点,我们可以将符号输入谷歌,并得到a link to the class' reference. 根据这个链接,函数定义为:
Class : Gnome::Glade::Xml
Section: "Static Public Member Functions"
Full declaration:
static Glib::RefPtr< Xml >
create (const std::string &filename, const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring())
要仔细检查,我们可以使用该参数列表来确定函数的错位名称:
static Glib::RefPtr< Xml >
Gnome::Glade::Xml::create (const std::string &filename,
const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring());
直接将其放入一个简单的 C++ 程序中(使用 Glib::RefPtr<T>、Glib::ustring 和 Gnome::Glade::Xml 的虚拟类),然后将 typeid(Gnome::Glade::Xml::create).name() 输出到 cout 不会生成正确的符号,这表明修改方案或 ABI 的变化。更具体地说,std::string 被修改为NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE,而不是预期的Ss。在a bit of digging around 之后,我发现这是由于 GCC 5.1 及更高版本的更改,其中宏_GLIBCXX_USE_CXX11_ABI 表示使用新的string(和新名称)而不是旧的。这也给出了问题原因的可能指示(见本文末尾)。
因此,考虑到这一点,最好使用旧方案手动修改函数的名称,看看它是否与符号匹配。
<public name> ::= <simple or qualified name> [<parameter type>]<sup>∞</sup><sub>1</sub>
There is a minimum of 1 "parameter type" symbols.
Name : Gnome::Glade::Xml::create
Parameters:
const std::string& : RKSs
"RK" is "Reference (R), const (K)", and "Ss" is a special symbol for std::string.
const Glib::ustring& : RK4Glib7ustringE
"RK" is followed by the type's "qualified name".
const Glib::ustring& : RK4Glib7ustringE
由于第三个参数是第三个的重复,所以它使用缩写规则,其中Sx_是一个缩写符号。根据 PDF,每个用户定义的类型名称、命名空间名称和非简单类型都分配了一个缩写,但实体名称本身没有。所以……
S0_ : 5Gnome
S1_ : 5Glade
S2_ : 3Xml
S3_ : Ss
S4_ : RKSs
S5_ : 4Glib
S6_ : 7ustring
S7_ : RK4Glib7ustringE
因此,第三个参数是S7_。考虑到这一点,最终的符号是:
Name : _ZN5Gnome5Glade3Xml6createE
Parameter list: RKSsRKN4Glib7ustringES7_
Parameters:
RKSs : const std::string&
RKN4Glib7ustringE : const Glib::ustring&
S7_ : const Glib::ustring&
Symbol : _ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
Two underscores were apparently dropped somewhere, one on each end.
将其提供给实用程序站点 Demangler.com 会生成以下解组符号:
Gnome::Glade::Xml::create(std::string const&, Glib::ustring const&, Glib::ustring const&)
由于 PDF 声明返回类型不包含在普通函数的修饰方案中,这似乎是正确的。
现在,如上所述,ABI 已更改,导致修改方案和/或库类型名称发生更改。所以,为了检查这一点,我做了一些测试。
// main.cpp
//#undef _GLIBCXX_USE_CXX11_ABI
//#define _GLIBCXX_USE_CXX11_ABI 0
//#include <iostream>
//#include <typeinfo>
#include <string>
namespace Glib {
template<typename T>
class RefPtr {};
class ustring {};
}
namespace Gnome {
namespace Glade {
class Xml {
public:
static Glib::RefPtr< Xml >
create (const std::string &filename,
const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring());
};
}
}
Glib::RefPtr< Gnome::Glade::Xml >
Gnome::Glade::Xml::create (const std::string &filename,
const Glib::ustring &root /*=Glib::ustring()*/,
const Glib::ustring &domain /*=Glib::ustring()*/) {
return Glib::RefPtr<Gnome::Glade::Xml>();
}
int main() {
// std::cout << typeid(const std::string&).name() << std::endl;
// std::cout << typeid(Gnome::Glade::Xml::create).name() << std::endl;
// std::cout << typeid(std::string).name() << std::endl;
}
通过这段代码,我首先使用typeid输出函数符号,然后注释掉前两个#includes和main()的主体,使用-c编译器选项编译文件,然后使用nm main.o 输出符号列表。虽然typeid 与符号不匹配,但nm 显示的名称是:
// With macros commented out:
_ZN5Gnome5Glade3Xml6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN4Glib7ustringESD_
// With macros active:
_ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
由于第二个与错误信息中提到的符号相同,这表明修改方案仍然相同,因此问题的解决方案是:
您尝试链接的目标文件是使用不同版本的 GCC(或您使用的任何 GCC 兼容编译器)编译的,或者是使用设置为 0 的 _GLIBCXX_USE_CXX11_ABI 宏编译的而另一个不是。