Name mangling
In the realm of compiler development, name mangling—also referred to as name decoration—serves as a method to generate unique identifiers for programming constructs in numerous contemporary programming languages.
This process embeds supplementary details into the identifier of a function, structure, class, or other data type. This allows the compiler to convey semantic information to the linker effectively.
Name mangling becomes essential in languages that permit multiple entities sharing the same identifier but differing in namespace or type signature (such as through function overloading). Each variant may require distinct machine-level calling conventions.
The object code produced by compilers is combined by a linker, which relies on detailed data like function identifiers, argument quantities, and their types. Early languages such as C identified routines solely by their names, disregarding parameters and return values. In contrast, languages like C++ enforce stricter criteria—considering parameter types, return types, and calling conventions—to support overloading and catch compilation errors. Because traditional linkers recognize only symbol names, these additional constraints are encoded through name mangling.
C
Languages lacking function overloading capabilities, including C and classic Pascal, typically do not require name mangling but may use it to indicate calling conventions. On Microsoft Windows, where multiple incompatible calling conventions exist, compilers mangle symbols with codes that specify the convention used.
The Windows mangling scheme, devised by Microsoft, has been informally embraced by compilers such as Digital Mars, Borland, and the GNU Compiler Collection (GCC) targeting Windows platforms. This approach extends to languages like Pascal, D, Delphi, Fortran, and C#, facilitating interoperability with Windows libraries employing various calling conventions.
Consider these C function definitions: <syntaxhighlight lang="c"> int _cdecl f (int x) { return 0; } int _stdcall g (int y) { return 0; } int _fastcall h (int z) { return 0; } </syntaxhighlight>
32-bit compilers generate:
_f _g@4 @h@4
In and , functions are represented as _name@X or @name@X, where denotes the decimal byte count of arguments—including those passed via registers for fastcall. For , only a leading underscore is prefixed.
The 64-bit Windows naming convention drops the initial underscore, which can lead to unresolved external references when porting code. For example, Fortran functions aliased to C using 32-bit naming conventions may fail under 64-bit environments. Solutions include avoiding 'alias' or employing the BIND directive:
<syntaxhighlight lang="fortran"> SUBROUTINE f() BIND(C,NAME="f") END SUBROUTINE </syntaxhighlight>
Within C, most compilers also apply similar mangling to static functions and variables as they do for non-static ones. Identical names across different translation units might share mangled names yet remain distinct internally to prevent linkage conflicts. To avoid cross-unit linking issues, compilers often emit 'local' symbols utilizing the relocation process during linking.
C++
Name mangling is predominantly utilized by C++ compilers. Initially, C++ compilers converted source code into C code, necessitating that symbol names adhere to C’s identifier conventions. Even when compilers began producing machine code directly, linkers commonly lacked native support for C++ symbols, making name mangling indispensable.
There is no universal standard for name decoration in C++; each compiler implements its own approach. Advanced language features such as classes, templates, namespaces, and operator overloading require incorporating metadata into symbol names to differentiate them. Due to the diversity of mangling methods across compilers, linking object files compiled by different tools is generally unsupported.
Simple example
Consider a C++ translation unit that declares two overloaded functions named :
<syntaxhighlight lang="cpp"> int f () { return 1; } int f (int) { return 0; } void g () { int i = f(), j = f(0); } </syntaxhighlight>
These separate functions are distinguished by embedding type information within their symbol names, producing mangled identifiers such as:
<syntaxhighlight lang="cpp"> int __f_v () { return 1; } int __f_i (int) { return 0; } void __g_v () { int i = __f_v(), j = __f_i(0); } </syntaxhighlight>
All C++ symbols undergo mangling except those declared inside an <syntaxhighlight lang="cpp" inline>extern "C"{}</syntaxhighlight> block.
Complex example
GNU GCC version 3.x compilers generate mangled names conforming to the IA-64 (Itanium) ABI standard, exemplified below:
<syntaxhighlight lang="cpp"> namespace wikipedia {
class article
{
public:
std::string format (); // = _ZN9wikipedia7article6formatEv
bool print_to (std::ostream&); // = _ZN9wikipedia7article8print_toERSo
class wikilink
{
public:
wikilink (std::string const& name); // = _ZN9wikipedia7article8wikilinkC1ERKSs
};
};
} </syntaxhighlight>
Mangled names begin with to prevent clashes with reserved identifiers; nested names use , followed by length-prefixed identifiers, and conclude with . For instance, the symbol for is:
_ZN9wikipedia7article6formatE
Function signatures follow; here, returning void is encoded as :
_ZN9wikipedia7article6formatEv
For , the parameter type maps to the alias , with a reference represented as , resulting in:
_ZN9wikipedia7article8print_toERSo
Variation of mangling across compilers
No single standardized method exists for mangling even basic C++ identifiers. Different compilers, their versions, or target platforms produce significantly distinct and incompatible mangled names for identical public symbols. The following table demonstrates how various compilers encode the functions void h(int), void h(int, char), and void h(void) differently:
Watcom C++ 10.6 <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">W?h$n(i)v</syntaxhighlight> <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">W?h$n(ia)v</syntaxhighlight> <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">W?h$n()v</syntaxhighlight>| Compiler | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">void h(int)</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">void h(int, char)</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">void h(void)</syntaxhighlight> |
|---|---|---|---|
| Intel C++ 8.0 for Linux | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">_Z1hi</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">_Z1hic</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">_Z1hv</syntaxhighlight> |
| HP aC++ A.05.55 IA-64 | |||
| IAR EWARM C++ | |||
| GCC 3.x and higher | |||
| Clang 1.x and higher | |||
| GCC 2.9.x | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Fi</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Fic</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Fv</syntaxhighlight> |
| HP aC++ A.03.45 PA-RISC | |||
| Microsoft Visual C++ v6-v10 | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">?h@@YAXH@Z</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">?h@@YAXHD@Z</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">?h@@YAXXZ</syntaxhighlight> |
| Digital Mars C++ | |||
| Borland C++ v3.1 | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">@h$qi</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">@h$qizc</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">@h$qv</syntaxhighlight> |
| OpenVMS C++ v6.5 (ARM mode) | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">H__XI</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">H__XIC</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">H__XV</syntaxhighlight> |
| OpenVMS C++ v6.5 (ANSI mode) | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">CXX$__7H__FIC26CDH77</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">CXX$__7H__FV2CB06E8</syntaxhighlight> | |
| OpenVMS C++ X7.1 IA-64 | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">CXX$_Z1HI2DSQ26A</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">CXX$_Z1HIC2NP3LI4</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">CXX$_Z1HV0BCA19V</syntaxhighlight> |
| SunPro CC | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__1cBh6Fi_v_</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__1cBh6Fic_v_</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__1cBh6F_v_</syntaxhighlight> |
| Tru64 C++ v6.5 (ARM mode) | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Xi</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Xic</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">h__Xv</syntaxhighlight> |
| Tru64 C++ v6.5 (ANSI mode) | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__7h__Fi</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__7h__Fic</syntaxhighlight> | <syntaxhighlight lang="text" class="" style="background:none; border:none; color:inherit; padding: 0px 0px;" inline="1">__7h__Fv</syntaxhighlight> |
Important notes:
- The Compaq C++ compiler on OpenVMS (both VAX and Alpha architectures) and Tru64 UNIX employed two distinct mangling conventions: an original ARM model based on the Annotated Reference Manual that became inadequate for newer constructs like templates, and a newer ANSI model supporting comprehensive template capabilities but lacking backward compatibility.
- On IA-64 platforms, a standardized application binary interface (ABI) defines a consistent name mangling scheme embraced by all IA-64 compilers; GCC version 3.x extended this convention to additional platforms.
- Microsoft Visual Studio and Windows SDK include the undname utility to translate mangled symbols back into human-readable function declarations.
- Intel and Clang compilers targeting Windows adopt Visual C++’s name mangling approach to maintain compatibility with Microsoft development tools.
Managing C Symbols When Linking from C++
A widely used C++ pattern is:
<syntaxhighlight lang="cpp">
- ifdef __cplusplus
extern "C" {
- endif
/* ... */
- ifdef __cplusplus
}
- endif
</syntaxhighlight>
This construct guarantees that enclosed symbols remain "unmangled," meaning the compiler generates binary outputs with their original names intact, as a C compiler would produce. Since C symbols avoid mangling, the C++ compiler must refrain from applying name mangling to references of these identifiers.
For instance, the standard C string library often declares:
<syntaxhighlight lang="cpp">
- ifdef __cplusplus
extern "C" {
- endif
void *memset (void *, int, size_t); char *strcat (char *, const char *); int strcmp (const char *, const char *); char *strcpy (char *, const char *);
- ifdef __cplusplus
}
- endif
</syntaxhighlight>
Therefore, code such as:
<syntaxhighlight lang="cpp"> if (strcmp(argv[1], "-x") == 0)
strcpy(a, argv[2]);
else
memset (a, 0, sizeof(a));
</syntaxhighlight>
correctly references the unmangled versions of , , and . Without the extern "C" linkage specification, the compiler would produce mangled names absent from the C runtime library (like libc), resulting in linking failures.
Standardization of Name Mangling in C++
While standardizing name mangling could theoretically improve compatibility across different C++ compilers, it does not alone ensure interoperability. Name mangling represents only one component of the application binary interface (ABI); other elements such as exception handling, virtual table organization, memory layout padding, and stack alignment also influence compatibility. Furthermore, mandating a fixed mangling approach may conflict with system constraints or prevent implementations that bypass mangling altogether, like linkers capable of directly interpreting C++ symbols.
As a result, the C++ standard refrains from defining a mandatory name mangling scheme. The Annotated C++ Reference Manual (ARM) even advocates for diversity in mangling methods to prevent linking incompatible ABIs.
Nonetheless, certain platforms have adopted a standardized full C++ ABI—including name mangling—to facilitate compatibility.
Practical Implications of C++ Name Mangling
Since C++ symbols are frequently exported from DLL and shared object files, name mangling plays a vital role beyond compiler internals. Different compilers—or different versions of the same compiler—often employ distinct name decoration conventions. This discrepancy can cause unresolved symbol errors when libraries and applications are built with incompatible compilers. For example, when installing the Boost C++ Libraries on a system featuring multiple C++ compilers such as GNU GCC alongside a vendor-specific compiler, recompilation is necessary for each toolchain.
This differentiation enhances robustness by ensuring that incompatible object files—due to differing ABIs for classes, exceptions, and other features—are detected during the linking phase rather than manifesting as runtime errors or elusive bugs.
Therefore, name decoration constitutes an essential facet of any C++ ABI.
In extensive projects, translating mangled linker error messages back into human-readable source identifiers can be complex, complicating debugging and build workflows. Tools known as demanglers—including those integrated into linkers—aid this process but may omit critical details needed for complete disambiguation due to limitations inherent in the mangling format.
Demangling Using c++filt
<syntaxhighlight lang="console"> $ c++filt -n _ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_ Map<StringName, Ref<GDScript>, Comparator<StringName>, DefaultAllocator>::has(StringName const&) const </syntaxhighlight>
Demangling with GCC ABI Built-in Function
<syntaxhighlight lang="cpp">
- include <stdio.h>
- include <stdlib.h>
- include <cxxabi.h>
int main() { const char *mangled = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_"; int status = -1; char *demangled = abi::__cxa_demangle(mangled, NULL, NULL, &status); printf("Demangled: %s\n", demangled); free(demangled); return 0; } </syntaxhighlight>
Output:
Java
Within Java, method and class signatures encompass the names along with argument and return types. This signature format is standardized due to the integrated design of the language, compiler, and .class file structure, all created to support object-oriented principles and broad compatibility.
Generating Distinct Names for Inner and Anonymous Classes
Since anonymous classes are nested inside their parent classes, the compiler assigns "qualified" public names to inner classes to prevent naming collisions with other classes in the same namespace. Anonymous classes receive compiler-generated "synthetic" public names because they only exist during compilation and not at runtime. For example, compiling this Java snippet:
<syntaxhighlight lang="java"> public class foo {
class bar {
public int x;
}
public void zark () {
Object f = new Object () {
public String toString() {
return "hello";
}
};
}
} </syntaxhighlight>
results in three .class files:
- foo.class, representing the primary outer class foo
- foo$bar.class, the named inner class foo.bar
- foo$1.class, the anonymous inner class local to method foo.zark
These file names comply with JVM conventions (which permit $ characters) and are generated safely by the compiler; Java discourages using $ in ordinary class names.
At runtime, resolving names is further complicated by the fact that fully qualified name uniqueness applies only within a particular classloader. Classloaders form a hierarchy, and each JVM thread maintains a context class loader. When identical class names exist across different classloaders, loading attempts start with the root (system) classloader before proceeding to the context loader.
Java Native Interface
The Java Native Interface (JNI) allows Java applications to invoke native code, usually written in C or C++. Two main challenges related to name resolution arise here, neither of which is formally standardized:
- Translation of JVM method names to native function names—Oracle’s documented approach offers some consistency
- Complexities introduced by standard C++ name mangling
Python
In Python, name mangling is employed to shield class attributes from accidental access or override by subclasses. This is done by prefixing attribute names with two or more leading underscores and optionally one trailing underscore. For example, names like , , and undergo mangling, whereas and do not. This technique helps avoid naming conflicts in subclassing but does not prevent access at runtime.
Python modifies these mangled attribute names by adding a single underscore followed by the defining class's name, as illustrated below:
<syntaxhighlight lang="pycon"> >>> class Test: ... def __mangled_name(self): ... pass ... def normal_name(self): ... pass >>> t = Test() >>> [attr for attr in dir(t) if "name" in attr] ['_Test__mangled_name', 'normal_name'] </syntaxhighlight>
Turbo Pascal, Delphi
To prevent name mangling in Pascal, the following syntax can be employed:
<syntaxhighlight lang="pascal"> exports
myFunc name 'myFunc', myProc name 'myProc';
</syntaxhighlight>
Free Pascal
Free Pascal facilitates function and operator overloading, which necessitates name mangling. Nonetheless, it can invoke symbols from modules written in other languages and also export its own symbols for external linkage. For comprehensive information, refer to the Free Pascal Programmer's Guide.
Fortran
Due to Fortran's case insensitive characteristic and enhancements introduced with Fortran 90, such as modules, name mangling plays a crucial role. It guarantees consistent symbol linking across different compilers when interfacing with Fortran libraries like LAPACK from languages such as C.
Various compilers apply different case transformations: identifiers are converted to lowercase on AIX and HP-UX systems (e.g., ), uppercase on Cray and Unicos (), while GNU g77 appends underscores (e.g., or following f2c conventions). Intel's Fortran compiler behavior varies by platform; on Windows, it defaults to uppercase without an underscore.
Modules introduced in Fortran 90 require additional mangling to prevent naming collisions by combining the module and procedure names with specific delimiters. For instance:
<syntaxhighlight lang="fortran"> module m contains
integer function five()
five = 5
end function five
end module m </syntaxhighlight>
This function could be mangled as (GNU Fortran), (Intel ifort), or (Oracle sun95). Since Fortran utilizes generic interfaces instead of overloading, mangled names do not include argument type information.
The BIND option introduced in Fortran 2003 allows overriding the default compiler-generated name mangling.
Rust
By default, Rust applies name mangling to function symbols; however, this can be suppressed using the attribute when exporting functions to C, C++, or Objective-C. When combined with or , this enables defining a C-style program entry point.
Rust offers multiple symbol mangling schemes selectable at compile time via :
- : C++-style mangling based on the Itanium IA-64 C++ ABI, implemented since Rust version 1.9.
- : An enhanced scheme beginning with , which supports encoding polymorphism and Unicode names using a modified punycode, available since Rust 1.37.
These schemes enhance symbol uniqueness and facilitate interoperability, supporting integration with other programming languages and development tools.
Objective-C
Objective-C methods are categorized as either class ("static") or instance methods, declared as follows:
+ (return-type) name0:parameter0 ... – (return-type) name0:parameter0 ...
Class methods are prefixed with +, while instance methods use -. Internally, compiled method names become symbols starting with for class methods and for instance methods, substituting colons with underscores. As an example, the class method in class compiles to , whereas the instance method compiles to .
To optimize performance, each method name is assigned a unique selector (of type ), which maps to implementation pointers (type ). The runtime leverages these selectors during message sending via functions such as , enabling dynamic dispatch and supporting polymorphism.
Because Objective-C lacks namespaces, class names remain unmangled. The runtime maintains argument and return type metadata separately from method names, allowing diverse method implementations across different classes.
Swift
In Swift, metadata related to functions is encoded within mangled symbols, encompassing details such as the function’s name, characteristics, module, parameter types, and return type. To illustrate:
Consider the mangled identifier for a method belonging to a class inside a module (Swift 2014). Its components are as follows:
- : Prefix indicating a Swift symbol.
- : Denotes a non-curried function.
- : Indicates a class method.
- : Module name prefixed by its length.
- : Class name prefixed by its length.
- : Function name prefixed by its length.
- : Function attribute specifying a standard function.
- : Type of the initial parameter (the class instance).
- : Marks the beginning of the parameter type list.
- : External name of the first parameter.
- : Built-in Swift.Int type assigned to the first parameter.
- : Return type specified as Swift.Int.
Starting with Swift 4.0, the mangling scheme has been formally documented and maintains a close resemblance to the Itanium ABI style.
See also
- Application programming interface (API)
- Application binary interface (ABI)
- Calling convention
- Foreign function interface (FFI)
- Java Native Interface (JNI)
- Language binding
- SWIG
External links
- Itanium C++ ABI documentation, detailing the name mangling approach
- Macintosh C/C++ ABI Standard Specification
- c++filt – Utility for demangling C++ symbols generated by GNU/Intel compilers
- undname – Microsoft Visual C++ tool for demangling names
- demangler.com – Web-based service for decoding GCC and MSVC C++ symbol names
- The Objective-C Runtime System – From Apple’s The Objective-C Programming Language 1.0 guide
- Calling conventions for various C++ compilers by Agner Fog, explaining name mangling patterns on x86 and x64 platforms
- C++ Name Mangling/Demangling – Explanation of Visual C++ compiler mangling techniques
- PHP UnDecorateSymbolName – PHP script for demangling Microsoft Visual C function identifiers
- Mixing C and C++ Code
- Levine, John R., Linkers and Loaders, Morgan Kaufmann, 2000. Chapter 5: Symbol management. Code and errata accessible online.
- Name mangling demystified authored by Fivos Kefallonitis