本周有位网友在交流群提到“为什么无法在自己的电脑中通过 c filt 解析符号 _ZN5folly6detail15str_to_integralIxEENS_8ExpectedIT_NS_14ConversionCodeEEEPNS_5RangeIPKcEE ?”
name mangle
在解释上面的问题前,我们先了解一下什么是 name mangle?
根据 wikipedia 的定义, name mangle
是现代计算机程序设计语言的编译器用于解决由于程序实体的名字必须唯一而导致的问题的一种技术。
上面的话术比较晦涩难懂,我们下面用具体的示例说明一下。
代码语言:javascript复制// A 文件class Hi {public: void sayHi(int) { } void sayHi(int, char){ }};// B 文件Hi test = Hi::instance();test.sayHi(1);test.sayHi(1, 'c');
A 文件声明了类 Hi
,B 文件分别调用调用 Hi
两个方法 void sayHi(int)
和 void sayHi(int, char)
。
如果像 c 语言一样的方式生成符号,则会导致同时存在两个相同的强符号 _sayHi
。A 文件会因为同一个符合定义两次导致编译失败。B 文件因为无法找到合适的链接符号导致编译失败。
为此,编译器会很聪明的帮我们做一些事情。通过分别将两个方法进行了一次符合映射操作。该符合映射操作可以将符合转化为相对独特的唯一字符串,解决无法编译的问题。
代码语言:javascript复制// gcc 标准Hi::sayHi(int) → _ZN2Hi5sayHiEiHi::sayHi(int, char) → _ZN2Hi5sayHiEic
通常,我们将“通过特殊规则将符合映射为相对独特的唯一字符串”称之为 mangle
,相对的,反向操作被称之为 demangle
。
注意:mangle 后仍然存在冲突的可能性
name mangle 的各类方言
因为各种历史原因, mangle
目前没有制定任何的官方标准。在这种情况下,每个编译器都会自行定义一套“方言”,甚至同一套编译器的不同版本也会可能采用不同的规则。
如下,Wikipedia 中总结了一份不同编译的对相同函数进行 mangle 的示例。
https://zh.wikipedia.org/wiki/名字修饰
编译器 | void h(int) | void h(int, char) | void h(void) |
---|---|---|---|
Intel C 8.0 for Linux | _Z1hi | _Z1hic | _Z1hv |
HP aC A.05.55 IA-64 | _Z1hi | _Z1hic | _Z1hv |
IAR EWARM C 5.4 ARM | _Z1hi | _Z1hic | _Z1hv |
GCC 3.x and 4.x | _Z1hi | _Z1hic | _Z1hv |
GCC 2.9x | h__Fi | h__Fic | h__Fv |
HP aC A.03.45 PA-RISC | h__Fi | h__Fic | h__Fv |
Microsoft Visual C v6-v10 | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
Digital Mars C | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
Borland C v3.1 | @h$qi | @h$qizc | @h$qv |
OpenVMS C V6.5 (ARM模式) | H__XI | H__XIC | H__XV |
OpenVMS C V6.5 (ANSI模式) | CXX$__7H__FI0ARG51T | CXX$__7H__FIC26CDH77 | CXX$__7H__FV2CB06E8 |
OpenVMS C X7.1 IA-64 | CXX$_Z1HI2DSQ26A | CXX$_Z1HIC2NP3LI4 | CXX$_Z1HV0BCA19V |
SunPro CC | __1cBh6Fi_v_ | __1cBh6Fic_v_ | __1cBh6F_v_ |
Tru64 C V6.5 (ARM模式) | h__Xi | h__Xic | h__Xv |
Tru64 C V6.5 (ANSI模式) | __7h__Fi | __7h__Fic | __7h__Fv |
Watcom C 10.6 | W?h$n(i)v | W?h$n(ia)v | W?h$n()v |
c filt
在了解 name mangle 具有不同的“方言”后,很容易就猜测到“demangle 失败的原因可能是不同版本的 c filt 工具存在不同解析方式”。
经过测试,笔者电脑中的 c filt 可以正常进行对符号进行 demangle 操作。
通过 which 命令,我们对比一下两台电脑中 c filt 的区别。
在 demangle 失败的电脑中,c filt 命令对应执行文件是 /usr/bin/c filt 。
而在笔者的电脑中,c filt 命令对应执行文件是 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c filt 。
很明显,对于 iOS 开发者,我们应该选择 Xcode 工具自带的 c filt 才更加合适
总结
本文介绍了 name mangle 存在不同的版本,同时, c filt 工具也存在不同的版本,两者必须互相匹配才能正常进行 name mangle/demangle 操作。
点击阅读原文,可以查看作者的另外一篇文章 llvm name mangle 学习笔记