This document gathers my findings about gcc c++ name mangling.
It is to be considered as supplementaty materials to the Itanium C++ ABI's mangling section, especially it explores what accounts as a symbol to be substituted in the case of regular functions, templates and abbreviations.
As in C
name mangling, it is just the name of the variable.
eg. int bar;
is mangled as bar
.
eg. void(*baz)(int);
is mangled as baz
.
eg. int* const bar;
is mangled as _ZL3bar
_Z
preambule starts the mangled name.L
indicates the variable isconst
- Only applies to types with indirections (pointer / reference) since
const <value_type>
is mangled as<value_type>
- Only applies to types with indirections (pointer / reference) since
3bar
variable name, length encoded.
eg. void(* const baz)(int) = nullptr;
is mangled as _ZL3baz
_Z
preambule starts the mangled name.L
indicates the variable isconst
3baz
variable name, length encoded.
eg. namespace a { int bar; }
is mangled as _ZN1a3barE
_Z
preambule starts the mangled name.N1a3barE
encoded symbol. It is enclosed inN
..E
because the symbol is within a scope1a
namespace name, length encoded.3bar
variable name, length encoded.
Note: the std
namespace is special. It is abbreviated St
and remove the need for N
..E
enclosing.
eg. namespace std { int bar; }
is mangled as _ZSt3bar
_Z <declaration> (<parameter>+ | v )
<parameter>
is defined as ([PR]K?)*(<basic_type>|<function>|<user_type>)
with:
P
for pointerR
for referenceK
for const<basic_type>
for one of C++ basic types<function>
are encoded betweenF
..E
, return type of the function is encoded before parameters<user_type>
are encoded betweenN
..E
when nested (TODO add definition) and describe the whole hierarchy of types.
eg. void foo()
is mangled as _Z3foov
_Z
preambule is always here.3foo
function name, length encoded.v
no parameter is encoded as a singlevoid
parameter.
Note: the return type is not encoded here (although there are cases where it is encoded: function pointers and funtion template instances)
_Z <declaration> I<template_parameter>+E <template_return_type> (<parameter>+ | v )
eg.
template <typename A> void foo(A);
template <> void foo(int) {}
is mangled _Z3fooIiEvT_
:
_Z
preambule is always here, it starts the mangled name, for OSX it would be__Z
.3foo
function name, length encoded.IiE
template parameterint
is enclosed inI
..E
v
the return typevoid
.T_
reference to the first template parameter. Second would beT0_
, thirdT1_
, fourthT2_
, etc ...
Declaration and user defined types are encoded with their scope
namespace a {
struct S {
void foo();
void const_foo() const;
};
}
foo
is mangled_ZN1a1S3fooEv
:N1a1S3fooE
:a::S::foo
, foo is nested since it's withinS
anda
so it is enclosed inN
..E
1a
1S
3foo
v
: because there is no parameters (encoded as a singlevoid
parameter).
const_foo
is mangled_ZNK1a1S9const_fooEv
:NK1a1S9const_fooE
:a::S::foo
, foo is nested since it's withinS
anda
so it is enclosed inN
..E
K
because typeS
isconst
in the context offoo
1a
1S
9const_foo
To save space a compression scheme is used where symbols that appears multiple times are then substituted by an item from the sequence : S_
, S0_
, S1_
, S2_
, etc ...
The main added value of this document is to identify what is to be counted as a substitution.
eg.
void foo(void*, void*)
foo
would be encoded as _Z3fooPvS_
. To be decomposed as
_Z
3foo
Pv
stands for "pointer to void". Since it's not a basic type it's accounted as a symbol.S_
refers to the first symbol encoded, herePv
.
Note: foo
is a declaration, not a type and so it doesn't account as a substituable symbol.
Some symbols are recognized as special and are never substituted
St = ::std::
Sa = ::std::allocator
Sb = ::std::basic_string
Ss = ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char> >
Si = ::std::basic_istream<char, ::std::char_traits<char> >
So = ::std::basic_ostream<char, ::std::char_traits<char> >
Sd = ::std::basic_iostream<char, ::std::char_traits<char> >
Function parameters are either basic types, user defined types or indirections to basic or user defined types.
-
Basic types are encoded using a single letter. See Itanium C++ ABI's types mangling. Basic types are never substituable.
- eg.
void foo(int)
is encoded_Z3fooi
- eg.
-
No parameter is seen by the compiler as a single
void
parameter.- eg.
void foo()
is seen asvoid foo(void)
and encoded_Z3foov
- eg.
-
Parameters are encoded one after the other.
- eg.
void foo(char, int, short)
is encoded_Z3foocis
. None ofchar
,int
orshort
are substituable.
- eg.
- Indirections (pointer/reference) and type qualifiers are prepended to the type. Each indirection / type qualifier accounts for a new symbol.
- eg.
void foo(int)
is encoded_Z3fooi
.- No substitution.
- eg.
void foo(const int)
is encoded_Z3fooi
.- No substitution.
- eg.
void foo(const int*)
is encoded_Z3fooPKi
Ki
becomesS_
PKi
becomesS0_
- eg.
void foo(const int&)
is encoded_Z3fooRKi
Ki
becomesS_
RKi
becomesS0_
- eg.
void foo(const int* const*)
is encoded_Z3fooPKPKi
Ki
becomesS_
PKi
becomesS0_
KPKi
becomesS1_
PKPKi
becomesS2_
- eg.
void foo(int*&)
is encoded_Z3fooRPi
Pi
becomesS_
RPi
becomesS0_
- eg.
Note: const int
alone is encoded as int
, more generally constness of the type is not part of the signature (but constness of indirect types are).
- Functions are encoded between
F
..E
and prepended withP
for function pointer (R
for function reference), return type of the function is encoded.- eg.
void foo(void(*)(int))
is encoded_Z3fooPFviE
FviE
becomesS_
PFviE
becomesS0_
- eg.
void foo(void*(*)(void*),void*(*)(const void*),const void*(*)(void*));
is encoded_Z3fooPFPvS_EPFS_PKvEPFS3_S_E
with the following substitutions
- eg.
_Z3fooPFPvS_EPFS_PKvEPFS3_S_E
S_ ^^ : Pv void*
S0_ ^^^^^^ : FPvS_E void*()(void*)
S1_ ^^^^^^^ : PFPvS_E void*(*)(void*)
S2_ ^^ : Kv const void
S3_ ^^^ : PKv const void*
S4_ ^^^^^^^ : FS_PKvE void*()(const void*)
S5_ ^^^^^^^^ : PFS_PKvE void*(*)(const void*)
S6_ ^^^^^^^ : FS3_S_E const void*()(void*)
S7_ ^^^^^^^^ : PFS3_S_E const void*(*)(void*)
namespace a {
struct A{};
void foo(A) {}
}
foo
would be encoded as _ZN1a3fooENS_1AE
a::foo
is encoded asN1a3fooE
- It is enclosed by
N
..E
(symbol is nested and not instd
) a
is encoded1a
foo
is encoded3foo
- It is enclosed by
a::A
is encodedNS_1AE
- enclosed in
N
..E
(symbol is nested and not instd
) a
is encodedS_
A
is encoded1A
- enclosed in
Note: if namespace is std
then it is abbreviated and nested symbol are no more enclosed in N
..E
namespace std {
struct A{};
void foo(A) {}
}
foo
is encoded as _ZSt3fooSt1A
std::foo
is encoded asSt3foo
std::A
is encoded asSt1A
Note: std
is not substituted since it is an abbreviation.
struct A {
struct B{};
void foo(B);
};
void A::foo(A::B)
is encoded _ZN1A3fooENS_1BE
N1A3fooE
: declaration1A
:A
is now asS_
3foo
: name (not substituable)
NS_1BE
: single parameter of typeB
S_
:A
1B
: name,B
is nowS0_
Template instances account for one substitution.
template<typename T>
struct A {
void foo(A);
};
template<> void A<int>::foo(A<int>) {}
template<> void A<int>::foo(A<int>)
is encoded as _ZN1AIiE3fooES0_
N1AIiE3fooE
: declaration1AIiE
: is the template instantiation1A
: is nowS_
IiE
: oneint
template parameter- It accounts for a substitution, it is now
S0_
3foo
: name (not substituable)
S0_
: refers toA<int>
Templated function parameters are substituted with T[0-9]*_
on first use and then substituted again normally.
struct A {
template<typename T>
void foo(T, T);
};
template<> void A::foo<int>(int, int) {}
template<> void A::foo<int>(int, int)
is encoded as _ZN1A3fooIiEEvT_S1_
N1A3fooIiEE
: declaration1A
: is nowS_
3foo
: name (not substituable)IiE
: oneint
template parameter, is nowT_
N1A3fooIiEE
the full instantiated template is nowS0_
v
: template instance return typeT_S1_
function parametersT_
: refers to the first template parameter, is nowS1_
S1_
Templated function parameters are substituted only if the declaration is templated.
template<typename T>
struct A {
void foo(T, T);
};
template<> void A<int>::foo(int, int) {}
template<> void A<int>::foo(int, int)
is encoded as _ZN1AIiE3fooEii
N1AIiE3fooE
: declaration1A
: is nowS_
IiE
: oneint
template parameter (basic types are not substituable)1AIiE3
: is nowS0_
3foo
: name (not substituable)
ii
: first and second parameter refers to the first template parameter but is not substituted.
struct B {};
template<typename T>
struct A {
void foo(T, T);
};
template <> void A<B>::foo(B, B) {}
template <> void A<B>::foo(B, B)
is encoded as _ZN1AI1BE3fooES0_S0_
N1AI1BE3fooE
: declaration1A
: is nowS_
I1BE
: oneB
template parameter is nowS0_
1AI1BE
: is nowS1_
3foo
: name (not substituable)
S0_S0_
:S0_
refers toB
.
Function template parameters are substituted.
template<typename A, typename B> A foo(B, A, B);
template<> int foo(char, int, char) {}
template<> int foo(int, int, int) {}
template<> int foo(char, int, char)
is encoded as _Z3fooIicET_T0_S0_S1_
3fooIicE
: is nowS_
T_
: The return type of the function.int
is nowS0_
T0_
:char
is nowS1_
template<> int foo(int, int, int)
is encoded as _Z3fooIiiET_T0_S0_S1_
3fooIiiE
: is nowS_
T_
: The return type of the function.int
is nowS0_
T0_
:int
is nowS1_