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
_Zpreambule starts the mangled name.Lindicates 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
3barvariable name, length encoded.
eg. void(* const baz)(int) = nullptr; is mangled as _ZL3baz
_Zpreambule starts the mangled name.Lindicates the variable isconst3bazvariable name, length encoded.
eg. namespace a { int bar; } is mangled as _ZN1a3barE
_Zpreambule starts the mangled name.N1a3barEencoded symbol. It is enclosed inN..Ebecause the symbol is within a scope1anamespace name, length encoded.3barvariable 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:
Pfor pointerRfor referenceKfor 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..Ewhen nested (TODO add definition) and describe the whole hierarchy of types.
eg. void foo() is mangled as _Z3foov
_Zpreambule is always here.3foofunction name, length encoded.vno parameter is encoded as a singlevoidparameter.
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_:
_Zpreambule is always here, it starts the mangled name, for OSX it would be__Z.3foofunction name, length encoded.IiEtemplate parameterintis enclosed inI..Evthe 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;
};
}
foois mangled_ZN1a1S3fooEv:N1a1S3fooE:a::S::foo, foo is nested since it's withinSandaso it is enclosed inN..E1a1S3foo
v: because there is no parameters (encoded as a singlevoidparameter).
const_foois mangled_ZNK1a1S9const_fooEv:NK1a1S9const_fooE:a::S::foo, foo is nested since it's withinSandaso it is enclosed inN..EKbecause typeSisconstin the context offoo1a1S9const_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
_Z3fooPvstands 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
voidparameter.- 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,intorshortare 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_Z3fooPKiKibecomesS_PKibecomesS0_
- eg.
void foo(const int&)is encoded_Z3fooRKiKibecomesS_RKibecomesS0_
- eg.
void foo(const int* const*)is encoded_Z3fooPKPKiKibecomesS_PKibecomesS0_KPKibecomesS1_PKPKibecomesS2_
- eg.
void foo(int*&)is encoded_Z3fooRPiPibecomesS_RPibecomesS0_
- 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..Eand prepended withPfor function pointer (Rfor function reference), return type of the function is encoded.- eg.
void foo(void(*)(int))is encoded_Z3fooPFviEFviEbecomesS_PFviEbecomesS0_- eg.
void foo(void*(*)(void*),void*(*)(const void*),const void*(*)(void*));is encoded_Z3fooPFPvS_EPFS_PKvEPFS3_S_Ewith 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::foois encoded asN1a3fooE- It is enclosed by
N..E(symbol is nested and not instd) ais encoded1afoois encoded3foo
- It is enclosed by
a::Ais encodedNS_1AE- enclosed in
N..E(symbol is nested and not instd) ais encodedS_Ais 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::foois encoded asSt3foostd::Ais 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:Ais now asS_3foo: name (not substituable)
NS_1BE: single parameter of typeBS_:A1B: name,Bis 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: oneinttemplate 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: oneinttemplate parameter, is nowT_N1A3fooIiEEthe 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: oneinttemplate 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: oneBtemplate 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.intis nowS0_T0_:charis nowS1_
template<> int foo(int, int, int) is encoded as _Z3fooIiiET_T0_S0_S1_
3fooIiiE: is nowS_T_: The return type of the function.intis nowS0_T0_:intis nowS1_