为什么 demangle 会失败?

2020-10-26 15:19:14 浏览数 (1)

本周有位网友在交流群提到“为什么无法在自己的电脑中通过 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 学习笔记

0 人点赞