一、导读
Name Mangling
(名称修饰)是编译器用来向具有相同名称的函数添加附加字符(函数重载)的一种机制。名称修改的目的是避免在执行程序和调用可能与另一个函数同名的函数时出现任何混淆。
二、含义解读
为了更好地理解这个概念,这里有两个重要的维基百科定义:
函数重载:
在某些编程语言中,函数重载或方法重载是创建具有不同实现的多个同名函数的能力。对重载函数的调用将运行适合于调用上下文的该函数的特定实现,允许一个函数调用根据上下文执行不同的任务。
Name Mangling:
在编译器构造中,name mangling
(也称为名称修饰)是一种用于解决由于需要为许多现代编程语言中的编程实体解析唯一名称而引起的各种问题的技术。它提供了一种以函数、结构、类或其他数据类型的名称对附加信息进行编码的方法,以便将更多语义信息从编译器传递给linker
。
三、Name Mangling Example
现在我们对名称修饰的工作原理以及它是什么有了更多的了解。让我们举个例子。
#include <iostream>
using namespace std;
void add(int a, int b){cout << a + b << endl;}
void add(double a, double b){cout << a + b << endl;}
int main()
{
add(1, 2);
add(5.5, 8.3);
return 0;
}
在上面的示例中,我们创建了两个具有相同名称“add”的函数。为避免混淆,编译器将修改这两个函数。可以使用“nm”命令查看它们。
$nm bin/Debug/mangle.exe
0047add0 t .text$_ZNSiD0Ev
004add30 t .text$_ZNSt8numpunctIcEC1Ej
004addd0 t .text$_ZNSt8numpunctIcEC2EPSt16__numpunct_cacheIcEj
004afd30 t .text$_ZSt14__add_groupingIcEPT_S1_S0_PKcjPKS0_S5_
004afea0 t .text$_ZSt14__add_groupingIwEPT_S1_S0_PKcjPKS0_S5_
0040147e t __GLOBAL__sub_I__Z3addii
00401382 T __Z3adddd
00401350 T __Z3addii
0047add0 T __ZNSiD0Ev
004186c0 T __ZNSt15__exception_ptr13exception_ptr9_M_addrefEv
004add30 T __ZNSt8numpunctIcEC1Ej
004addd0 T __ZNSt8numpunctIcEC2EPSt16__numpunct_cacheIcEj
004afd30 T __ZSt14__add_groupingIcEPT_S1_S0_PKcjPKS0_S5_
004afea0 T __ZSt14__add_groupingIwEPT_S1_S0_PKcjPKS0_S5_
004271d0 T ____w64_mingwthr_add_key_dtor
0042ef60 T ___multadd_D2A
004352d0 T _pthread_attr_getstackaddr
004352e0 T _pthread_attr_setstackaddr
为清楚起见,我截断了输出并将我们的两个“add”函数加粗。
四、命名规则
五、Example 剖析
在我们的示例中,我们使用了 GCC 编译器。为了理解我们的错位函数,让我们剖析它们:
void add(int a, int b) become __Z3adddd
void add(double a, double b) become __Z3addii
- 损坏的名称以 _Z 开头
- 数字 3 是函数名称的长度(“add” = 3 个字符)。
- 最后,字母“dd”和“ii”是我们函数中使用的变量类型。
显然有更复杂的名称,具体取决于它在二进制文件中使用的变量类型和数据结构。
此外,网站 https://demangler.com/ 也可以帮助您了解损坏的名称。
或者,您也可以使用工具“c++filt”或二进制文件中的“nm -C”来对函数名称进行分解:
$ c++filt -_ __Z3adddd
# "-_" to ignore the first underscoreadd(double, double)