C/C++ 名字修饰

C 语言的名字修饰

C语言并不支持重载,因此C程序中禁止函数与函数同名,也就没有必要做name mangling。但C语言的函数调用协议(calling conventions)五花八门,用某一种调用协议编译的静态库或动态库的函数,如果用另外的调用协议去调用将会导致错误甚至系统崩溃。因此C语言编译器对函数的名字做少量的修饰,用于区别该函数支持哪种调用协议,这可以给编译、链接、特别是库函数的载入提供额外的检查信息。

C语言常用的调用协议有三种:cdecl, stdcall 与 fastcall。

  • cdecl 的函数被改名为_name;
  • stdcall的函数被改名为_name@X;
  • fastcall的函数被改名为@name@X。

其中X是函数形参所占用的字节长度(包括那些用寄存器传递的参数, 如fastcall协议).

1
2
3
int __cdecl foo(int i); // mangled name is _foo;
int __stdcall foo(int j); // mangled name is _foo@4
int __fastcall foo(int i) ; // mangled name is @foo@4

注意:Windows 的 64位 Microsoft C 的调用约定中没有前导下划线。

C++ 的名字修饰

C++语言并没有规定一个标准的名字修饰方式,所以各款编译器都使用各自的名字修饰方式。(相同编译器的不同版本也可能使用不同的修饰规则)

GCC/Clang 编译器

MSVC 编译器

Visual C++ 名字修饰符主要包含以下部分:

  1. 问号前缀;
  2. 函数名称或不包括类名的方法名称。构造、析构函、运算符重载等具有特定的函数名;
  3. 如果不是特殊函数名,那么加一个分隔符@;
  4. 如果是类的方法,那么由所属类开始依次加上类名和父类名,每个类名后面跟一个@符号,所有类名加好后,再加上@Q或者@S(静态方法)。如果不是类的方法,那么直接加上@Y;
  5. 调用约定代码。对于不属于任何类的函数,C调用约定(__cdecl)的代码为A,__fastcall约定的代码为I,__stdcall 的代码为G,对于类方法,调用约定前会加一个字符A,this调用的代码为E.
  6. 返回值编码。
  7. 参数列表编码,以@符号结束。
  8. 后缀Z。

C++名称修饰组成规律:

  1. 都是以?开始,以字符Z结束,中间由@符号分割为多个部分。整个名称的长度最长为2048个字节。
  2. 类的成员函数,其基本结构为:?方法名@类名@@调用约定 返回类型 参数列表 Z。
  3. 非类的成员函数,其基本结构: ?函数名@@Y调用约定 返回类型 参数列表Z。

特殊函数名:

特殊方法名 编码
构造函数 ?0
析构函数 ?1
重载 new ?2
重载 delete ?3

数据类型:

编码 数据类型
A Type modifier (reference)
B Type modifier (volatile reference)
D char
E unsigned char
F short
G unsigned short
H int
I unsigned int
J long
K unsigned long
M float
N double bool
O long double Array
P Type modifier (pointer)
Q Type modifier (const pointer)
R Type modifier (volatile pointer)
S Type modifier (const volatile pointer)
T union
U struct
V class
W enum
X void

预编译宏

GCC/Clang 以及微软都提供了预定义宏,用于获取源码中的方法名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// GCC 支持: __PRETTY_FUNCTION__ 和 __FUNCTION__
// MSVC 支持: __FUNCTION__ 和 __FUNCDNAME__ 和 __FUNCSIG__

void exampleFunction()
{
printf("Function name: %s\n", __FUNCTION__);
printf("Decorated function name: %s\n", __FUNCDNAME__);
printf("Function signature: %s\n", __FUNCSIG__);

// 输出为:
// -------------------------------------------------
// Function name: exampleFunction
// Decorated function name: ?exampleFunction@@YAXXZ
// Function signature: void __cdecl exampleFunction(void)

}

修饰解析

  1. GCC/Clang 编译的符号通过 c++filt 去修饰。
  2. MSVC 编译的符号使用微软 Visual C++ 中的解析修饰名字的工具软件 undname.exe

查看Visual C++的函数的修饰后的名字:

  1. 直接用工具软件(如微软开发环境提供的dumpbin)查看obj、exe等二进制文件。使用dumplib查看.obj或.lib文件时,使用”/SYMBOLS”命令行选项。
  2. 编译时使用”/FA[c|s|u]”编译选项,生成带有丰富注释信息的汇编源程序,其文件扩展名是.cod或者.asm,可以查看每个C/C++函数的修饰名。

new 和 delete 名字修饰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// __Znwm
operator new(unsigned long)
// __ZnwmRKSt9nothrow_t
operator new(unsigned long, std::nothrow_t const&)
// __ZnwmSt11align_val_t
operator new(unsigned long, std::align_val_t)
// __ZnwmSt11align_val_tRKSt9nothrow_t
operator new(unsigned long, std::align_val_t, std::nothrow_t const&)


// __Znam
operator new[](unsigned long)
// __ZnamRKSt9nothrow_t
operator new[](unsigned long, std::nothrow_t const&)
// __ZnamSt11align_val_t
operator new[](unsigned long, std::align_val_t)
// __ZnamSt11align_val_tRKSt9nothrow_t
operator new[](unsigned long, std::align_val_t, std::nothrow_t const&)


// __ZdlPv
operator delete(void*)
// __ZdlPvRKSt9nothrow_t
operator delete(void*, std::nothrow_t const&)
// __ZdlPvSt11align_val_t
operator delete(void*, std::align_val_t)
// __ZdlPvSt11align_val_tRKSt9nothrow_t
operator delete(void*, std::align_val_t, std::nothrow_t const&)
// __ZdlPvm
operator delete(void*, unsigned long)
// __ZdlPvmSt11align_val_t
operator delete(void*, unsigned long, std::align_val_t)


// __ZdaPv
operator delete[](void*)
// __ZdaPvRKSt9nothrow_t
operator delete[](void*, std::nothrow_t const&)
// __ZdaPvSt11align_val_t
operator delete[](void*, std::align_val_t)
// __ZdaPvSt11align_val_tRKSt9nothrow_t
operator delete[](void*, std::align_val_t, std::nothrow_t const&)
// __ZdaPvm
operator delete[](void*, unsigned long)
// __ZdaPvmSt11align_val_t
operator delete[](void*, unsigned long, std::align_val_t)

参考

  1. https://zh.wikipedia.org/wiki/Visual_C%2B%2B%E5%90%8D%E5%AD%97%E4%BF%AE%E9%A5%B0
  2. https://chromium.googlesource.com/chromium/llvm-project/libcxx/+/refs/heads/master/lib/libc++abi-new-delete.exp
  3. https://developer.apple.com/library/archive/technotes/tn2185/_index.html#//apple_ref/doc/uid/DTS10004200-CH1-SECTION13