为什么 demangle 会失败?
本周有位网友在交流群提到“为什么无法在自己的电脑中通过 c++filt 解析符号 _ZN5folly6detail15str_to_integralIxEENS_8ExpectedIT_NS_14ConversionCodeEEEPNS_5RangeIPKcEE ?”
name mangle
在解释上面的问题前,我们先了解一下什么是 name mangle?
根据 wikipedia 的定义, name mangle
是现代计算机程序设计语言的编译器用于解决由于程序实体的名字必须唯一而导致的问题的一种技术。
上面的话术比较晦涩难懂,我们下面用具体的示例说明一下。
// 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 文件因为无法找到合适的链接符号导致编译失败。
为此,编译器会很聪明的帮我们做一些事情。通过分别将两个方法进行了一次符合映射操作。该符合映射操作可以将符合转化为相对独特的唯一字符串,解决无法编译的问题。
// gcc 标准Hi::sayHi(int) → _ZN2Hi5sayHiEiHi::sayHi(int, char) → _ZN2Hi5sayHiEic
通常,我们将“通过特殊规则将符合映射为相对独特的唯一字符串”称之为 mangle
,相对的,反向操作被称之为 demangle
。
注意:mangle 后仍然存在冲突的可能性
name mangle 的各类方言
因为各种历史原因, mangle
目前没有制定任何的官方标准。在这种情况下,每个编译器都会自行定义一套“方言”,甚至同一套编译器的不同版本也会可能采用不同的规则。
如下,Wikipedia 中总结了一份不同编译的对相同函数进行 mangle 的示例。
https://zh.wikipedia.org/wiki/%E5%90%8D%E5%AD%97%E4%BF%AE%E9%A5%B0
编译器 |
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 学习笔记
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python爬虫之scrapy的日志信息与配置
- Python爬虫之scrapyd部署scrapy项目
- 最近发现一个很有趣的随机小姐姐视频源码 分享给大家
- Codeforces Round #633 (Div. 2)C Powered Addition (贪心,二进制)
- Spring 整合 JUnit
- Java Stax解析XML示例
- Codeforces Round #633 (Div. 2) B Sorted Adjacent Differences(直观感知+排序插放)
- Spring 声明式事务
- Leetcode 1320 二指输入的的最小距离(多情况讨论,DP)
- Spring 基本注解
- Spring 基于注解的 IOC 与 AOP
- Leetcode 1319 连通网络的操作次数(并查集)
- Leetcode 77. 组合 (排列组合,回溯)
- C++17特性 string_view substr只要常数复杂度,且省内存
- MQ 系列之 ActiveMQ 基本使用