5.
Calling conventions
for different C++ compilers and operating systems
By Agner Fog. Technical University of Denmark.
Copyright © 2004 - 2023. Last updated 2023-02-01.

Contents
1 Introduction ....................................................................................................................... 3
2 The need for standardization ............................................................................................. 5
3 Data representation ........................................................................................................... 6
4 Data alignment .................................................................................................................. 8
5 Stack alignment ................................................................................................................. 9
6 Register usage ................................................................................................................ 10
6.1 Can x87 floating point registers be used in 64-bit Windows? .................................... 13
6.2 YMM vector registers ................................................................................................ 14
6.3 Transitions between VEX and non-VEX code ........................................................... 14
6.4 ZMM vector registers ................................................................................................ 15
6.5 Register usage in kernel code ................................................................................... 16
7 Function calling conventions ........................................................................................... 17
7.1 Passing and returning objects ................................................................................... 20
7.2 Passing and returning SIMD types ............................................................................ 23
8 Name mangling ............................................................................................................... 25
8.1 Microsoft name mangling .......................................................................................... 30
8.2 Borland name mangling ............................................................................................ 34
8.3 Watcom name mangling ........................................................................................... 35
8.4 Gnu 2 name mangling............................................................................................... 36
8.5 Gnu 3 and later name mangling ................................................................................ 38
8.6 Intel name mangling for Windows ............................................................................. 40
8.7 Intel name mangling for Linux ................................................................................... 42
8.8 Symantec and Digital Mars name mangling .............................................................. 43
8.9 Codeplay name mangling ......................................................................................... 43
8.10 Other compilers ...................................................................................................... 43
8.11 Turning off name mangling with extern "C" ............................................................. 43
8.12 Conclusion .............................................................................................................. 45
9 Exception handling and stack unwinding ......................................................................... 45
10 Initialization and termination functions ........................................................................... 46
11 Virtual tables and runtime type identification.................................................................. 46
12 Communal data ............................................................................................................. 46
13 Memory models ............................................................................................................. 47
13.1 16-bit memory models ............................................................................................ 47
13.2 32-bit memory models ............................................................................................ 48
13.3 64-bit memory models in Windows ......................................................................... 48
13.4 64-bit memory models in Linux and BSD ................................................................ 48
13.5 64-bit memory models in Intel-based Mac (Darwin) ................................................ 48
13.6 64-bit memory models in Cygwin ............................................................................ 49
14 Relocation of executable code....................................................................................... 49
14.1 Import tables ........................................................................................................... 51
15 Object file formats ......................................................................................................... 51
15.1 OMF format............................................................................................................. 51
15.2 COFF format ........................................................................................................... 52
15.3 ELF format .............................................................................................................. 53
15.4 Mach-O format ........................................................................................................ 53
15.5 a.out format............................................................................................................. 54
15.6 Comparison of object file formats ............................................................................ 54

15.7 Conversion between object file formats................................................................... 54
15.8 Intermediate file formats ......................................................................................... 55
16 Debug information ......................................................................................................... 55
17 Data endian-ness .......................................................................................................... 55
18 Predefined macros ........................................................................................................ 55
19 Available C++ Compilers ............................................................................................... 57
19.1 Microsoft ................................................................................................................. 57
19.2 Borland/Embarcadero ............................................................................................. 57
19.3 Watcom .................................................................................................................. 57
19.4 Gnu ......................................................................................................................... 57
19.5 Clang ...................................................................................................................... 57
19.6 Digital Mars ............................................................................................................. 57
19.7 Codeplay ................................................................................................................ 57
19.8 Intel C++ compiler Classic ...................................................................................... 57
19.9 Intel oneAPI C++ compiler, LLVM based ................................................................ 58
20 Literature ....................................................................................................................... 59
20.1 ABI's for Unix, Linux, BSD and Mac OS X (Intel-based). ......................................... 59
20.2 ABIs for Windows.................................................................................................... 59
20.3 Object file format specifications............................................................................... 60
21 Copyright notice ............................................................................................................ 60
22 Acknowledgments ......................................................................................................... 60

2

1 Introduction
This is the fifth in a series of five manuals:
1. Optimizing software in C++: An optimization guide for Windows, Linux and Mac
platforms.
2. Optimizing subroutines in assembly language: An optimization guide for x86
platforms.
3. The microarchitecture of Intel, AMD and VIA CPUs: An optimization guide forassembly programmers and compiler makers.
4. Instruction tables: Lists of instruction latencies, throughputs and micro-operation
breakdowns for Intel, AMD and VIA CPUs.
5. Calling conventions for different C++ compilers and operating systems.
The latest versions of these manuals are always available from www.agner.org/optimize.
Copyright conditions are listed on page 60 below.
The present manual describes technical details about compilers that are often poorly
documented or not documented at all. This includes differences between various C++
compilers that affect binary compatibility, such as memory model, data storage, function
calling conventions, and name mangling. These details are described in detail for eachcompiler or for each platform, where appropriate.
The purposes of publishing this information are:•

Point out incompatibilities between compilers.

•

Make new compilers compatible with old ones.

•

Solve compatibility problems between function libraries produced by different
compilers.

•

Facilitate linking different programming languages together.

•

Facilitate the making of assembly subroutines that are compatible with multiple
compilers and multiple operating systems.

•

Solve compatibility problems for data stored in binary files.

•

Facilitate the construction of debugging, profiling and disassembly tools.

•

Facilitate the construction of object file conversion utilities.

•

Provoke compiler vendors to use open standards.

•

Inspire future standardization.

Hardware platforms covered:•x86 microprocessors with 16 bit, 32 bit and 64 bit architectures from Intel, AMD, VIA
and possibly other vendors.

3

The IA64 architecture, which is implemented in Intel's Itanium processor, is not compatible
with the x86 architecture, and is not covered in this report.
Operating systems covered:
•
•
•
•
•

DOS, 16 bit.
Windows, 16 bit, 32 bit and 64 bit.
Linux, 32 bit and 64 bit.
FreeBSD etc. 32 bit and 64 bit.
Mac OS X, Intel based, 32 bit and 64 bit.

C++ compilers tested:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

Borland, 16 bit v. 3.0 and 5.0
Microsoft, 16 bit, v. 8.0
Watcom, 16 bit v. 1.2
Borland 32 bit v. 5.0
Microsoft, 32 bit, v. 9.0, 13.10, 16.3
Gnu, 32 bit, v. 2.95, 3.3.3, 4.1.0 and several other versions under Linux, FreeBSD
and Windows.
Watcom, 32 bit, v. 1.2
Symantec, 32 bit, v. 7.5
Digital Mars, 32 bit, v. 8.3.8
Codeplay VectorC, 32bit, v. 2.1.7
Intel, 32 bit for Windows and Linux, v. 8.1 and 9.1
Microsoft, 64 bit, v. 14.00, 16.3
Gnu, 64 bit, v. 3.3.3, 4.1.0, 7.4.0, 9.2.0 for Linux and Windows
Clang, 64 bit, v. 5.0, 9.0 for Linux and WindowsIntel, 64 bit for Windows and Linux, v. 8.1 and 9.1

This document provides information that is typically difficult to find. The documentation of
calling conventions and binary interfaces of compilers and operating systems is often
shamefully poor and sometimes completely absent.
As most of the information given here is based on my own experiments, it is obviously not
authoritative, and it is not guaranteed to be accurate or complete. This document tells how
things are, not how they are supposed to be. Some details appear to be the haphazard
consequences of how compilers happen to be implemented rather than results of carefulplanning. Calling "conventions" may not be the most appropriate term in this case, but it
may be necessary to copy the quirks of existing compilers when full compatibility is desired.
I have no knowledge about whether any information provided here is protected by patents
or other legal restrictions, but I have found no specific patent markings on the compilers.
I have gathered this information mainly by converting C++ code to assembly. All thecompilers I have tested are capable of converting C++ to assembly, either directly or via
object files. The reader is encouraged to do your own research, if necessary, to get
additional information needed or to clarify any questions you may have. The easiest way of
doing this research is to make the compiler convert a C++ test file to assembly. Other
possible methods are to use object file dump utilities, disassembly utilities, or provoke error
messages from a linker. If you find any errors in this document then please let me know.
Please note that I don't have the time and resources to help people with their programming
problems. If you Email me with such questions, you will not get any answer. You may send
your questions to appropriate internet forums instead.

4

2 The need for standardization
In the days of the old DOS operating system, it was often possible to combine development
tools from different vendors with few compatibility problems. With 32-bit Windows, thesituation has gone completely out of hand. Different compilers use different data
representations, different function calling conventions, and different object file formats.
While static link libraries have traditionally been considered compiler-specific, thewidespread use of dynamic link libraries (DLL's) has made the distribution of function
libraries in binary form more common. Unfortunately, the standardization of data
representation and calling conventions that would make DLL's compatible is still lacking.
In the Linux, BSD and Mac operating systems, there are fewer compatibility problems
because a more or less official standard is defined. Most of this standard is followed by Gnu
compilers version 3.x and later and by Clang compilers. Earlier versions of the Gnu compiler
are not compatible with this.
Fortunately, there is a growing recognition of the need for standardization of application
binary interfaces (ABI's). The ABI's for the 64-bit operating systems are specified in much
more detail than we have seen in older operating systems. However, some of these ABI's
still lack specification of name mangling schemes and other details. Traditionally, compiler
vendors have not published or standardized their name mangling schemes. A common
excuse was that the object files would not be compatible anyway because of differences indata formats and calling conventions. Now that data formats and calling conventions are
specified in the ABI's, there is no excuse any more for not publishing and standardizing
name mangling schemes as well. It is my hope that this document will be a contribution
towards this end.
Compilers and other development tools is an area where de facto standards play animportant role. Almost all compilers for UNIX-like x86 platforms are designed to becompatible with the Gnu compiler. And the calling "conventions" of the Microsoft compiler
has almost become a de facto standard for the Windows operating system. The C++
compilers from Intel, Symantec, Digital Mars and Codeplay are all designed to be binary
compatible with Microsoft's C++ compiler, despite the fact that Microsoft has refused to
publish important details. At least some of these compiler makers have relied on reverse
engineering for obtaining the necessary information. There is a pressing need for publishing
the relevant standards, and the present document is my contribution towards this end.
It is highly recommended that designers of development tools follow all available standards.
Where no official standard exists, use an existing compiler for reference. Use the Microsoft
compiler as a reference for Windows systems and the Gnu compiler as a reference forUNIX-like systems. For features that are not supported by these compilers, use the Intel
compiler for reference. The calling conventions of these compilers may be considered defacto standards for Windows and UNIX platforms.

5

3 Data representation
Table 1. Data sizes
32 bit

1
4
8
8

4
4
8
10

4
4
8
8

4

4
4

4
4

Intel Linux

2
4
8
10

Gnu, Clang

1
1
2
2
4
4

Intel Windows

1
1
2
2
4
4
8
4
4
8
16
8
16
32
64
4

Microsoft

2
4
8
10

Intel Linux

1
1
2
2
4
4
8
4
4
8
8
8
16
32
64
4

2
2
4

Gnu, Clang

Borland1
1

64 bitWatcomIntel Windows

2
2
4

1
1
2
2
2
4

2

Microsoft

2
1

2
4
2
2

WatcomBorlandbool
char
wchar_t
short int
int
long int
int64_tenum (typical)
float
doublelong double__m64__m128__m256__m512pointerfar pointerfunction pointerdata member pointer(min)data member pointer(max)
member function
pointer (min)member function
pointer (max)

16 bitMicrosoft

segment word size
compiler

1
1
2
2
4
4

4

1
1
2
2
4
4
8
4
4
8
12
8
16
32
64
4

1
1
2
2
4
4
8
4
4
8
12
8
16
32
64
4

1
1
2
2
4
4
8
4
4
8
8
16
32
64
8

1
1
2
2
4
4
8
4
4
8
16
8
16
32
64
8

1
1
4
2
4
8
8
4
4
8
16
8
16
32
64
8

1
1
4
2
4
8
8
4
4
8
16
8
16
32
64
8

4
8

4
4

4
4

4
4

8
4

8
4

8
8

8
8

2
4
2
4

2
4
2
6

4

6

12

12

8

12

4

4

12

12

8

8

12

6

4

4

12

4

8

8

8

8

16

16

12

6

16

16

12

16

8

8

24

24

16

16

Table 1 shows how many bytes of storage various objects use for different compilers.
Differences in data representation can cause problems when exchanging binary data files
between programs, when exchanging data with a DLL compiled with a different compiler,
and when porting C++ code that relies on a specific data format.

Bool
The type bool typically uses one byte of storage where all bits are significant. 0 indicatesfalse and all other values indicate true. Most compilers will always store the value true as
1. The ABI for 64 bit Linux/BSD specifies that other values than 0 and 1 are allowed only for
function parameters and returns, not for memory objects. The opposite would be morelogical since the most likely source of Booleans with other values than 0 and 1 is uninitialized memory objects.
A better convention would be to never allow other values than 0 and 1, or to rely only on asingle bit. This would make it possible to implement Boolean expressions without the use of
expensive branch instructions except where the evaluation of the second operand of && or|| has side effects. None of the compilers I have tested take advantage of the fact that the6only possible values are 0 and 1, even if the performance could be improved significantly by
relying on this fact.

Integers
Signed integers are stored in 2-complement representation. The size is 8, 16, 32 or 64 bits,
except in bitfields that can have other sizes.

Floating point numbers
Floating point numbers are stored according to the IEEE-754 standard. The most significant
bit of the mantissa is explicit (=1) in long double and implicit in float and double.
The x86 architecture specifies 10 bytes for long double. Microsoft compilers do not support
this precision, but store long double as double, using 8 bytes. Other compilers use morethan 10 bytes for the sake of alignment. The extra bytes are unused, even if subsequent
objects would fit into this unused space. The 32-bit and 64-bit Intel compilers for Windows
store long double as 8 bytes by default for compatibility with the Microsoft compiler. Use theoption /Qlong-double to get 16 bytes long double in Intel compilers.

Member pointers
A class data member pointer basically contains the offset of the member relative to thebeginning of the object. A member function pointer basically contains the address of themember function.
Data member pointers and member function pointers may use extra storage in the generalcase in order to account for rare cases of multiple inheritance etc. The minimum value intable 1 applies to simple cases, the maximum value applies to the case where the compiler
has no information about the class other than its name. Some compilers have options tocover this case in different ways. The extra information is stored in ways that are poorly
documented and poorly standardized. The "Itanium C++ ABI" includes more detailed
information about the representation of member pointers. This information may apply toother platforms as well. More information on the implementation of member pointers in
different compilers can be found in "Member Function Pointers and the Fastest Possible
C++ Delegates", by Don Clugston, www.codeproject.com/Articles/7150/Member-FunctionPointers-and-the-Fastest-Possible
Borland compilers add an offset of 1 to data member pointers in order to distinguish apointer to the first data member from a NULL pointer, represented by 0. The other compilers
have no offset, but represent a NULL data member pointer by the value -1.

1 and 2-byte types in Gnu compiler
Gnu compilers always zero-extend or sign-extend function return values to 32 bits if thevalues are less than 32 bits in order to conform to a certain interpretation of the C standard.
The 64 bit Gnu compiler sign-extends signed values to 32 bits rather than to 64 bits. The
extension to 32 bits appears to be completely superfluous since the calling function will
repeat the zero-extension or sign-extension operation if needed rather than relying on thehigher bits being valid.

Arrays and strings
Arrays are stored as consecutive objects in memory. No information about the size of thearray is included in the binary representation. Multidimensional arrays are stored in rowmajor order with the last index as least significant. Arrays are passed to functions as
pointers without copying. C-style strings are stored as arrays with a terminating element of0.
Most programming languages other than C and C++ store arrays and strings in ways that
include a specification of the size.
7Composite objects
Objects of structures and classes are stored by placing the data members consecutively inmemory. Unused bytes may be inserted between elements and after the last element, if
needed, for the sake of alignment. The requirements for alignment are described below.
Additional information for virtual tables and runtime type identification may be added, as
described in chapter 11.

4 Data alignment
Table 2. Alignment of static data
32 bit64 bitBorland

WatcomMicrosoft

Intel Windows

Borland

WatcomGnu, ClangIntel Linux

Microsoft

Intel Windows

Gnu, ClangIntel Linux

1 byte char
2 byte int
4 byte int
8 byte int
float
doublelong double__m64__m128__m256__m512pointerfar pointerbig array
big structure

16 bitMicrosoft

segment word size
compiler

1
2
2
2
2
2
2

1
2
2
2
2
2
2

1
2
4
8
4
8
8

1
4
4
8
4
8

4
4
4
8
4
8
16
8
16
32
64
4

1
2
4
4
4
4
4

1
2
4
8
4
8
8

1
2
4
8
4
8
4
8
16
32
64
4

4
4
4
8
4
8
4
8
16
32
64
4

1
4
4
8
4
8

4
4
4
8
4
8
16
8
16
32
64
8

1
2
4
8
4
8
16
8
16
32
64
8

4
4
4
8
4
8
16
8
16
32
64
8

2
2
2
2

8
16
32
64
4

4

4

2
2

2
2

1-2

2-8

4-8

512

1-4

2-8

1

2

4

32

1

8

32
32

32
32

8
16
32
64
8
4-8

256

4

32

32
32

32
32

Table 2 shows the default alignment in bytes of static data. The alignment affects
performance, but not compatibility.

8

Table 3. Alignment of structure members
32 bitIntel Linux

4

Gnu

2
2

Intel Windows

1
1

Microsoft22Intel Linux

1
2
4
8
4
8

Gnu v.3.x

1
2
2
2
2
2
2

WatcomMicrosoft

1
1
1
1
1
1
1

Borland

Watcom

1
2
2
2
2
2
2

64 bitIntel Windows

Borland

1 byte char
2 byte int
4 byte int
8 byte int
float
doublelong double__m64__m128__m256pointerfar pointer

16 bitMicrosoft

segment word size
compiler

1
2
4
8
4
8
16
8
16
32
4

1
1
1
1
1
1
1

1
2
4
8
4
8
8

1
2
4
4,8
4
8
16

1
2
4
8
4
8

4

4

1
2
4
8
4
8
16
8
16
32
8

1
2
4
8
4
8
16

1

1
2
4
8
4
8
16
8
16
32
4

1
2
4
8
4
8
16
8
16
32
8

8

8

Table 3 shows the alignment in bytes of data members of structures and classes. The
compiler will insert unused bytes, as required, between members to obtain this alignment.
The compiler will also insert unused bytes at the end of the structure so that the total size ofthe structure is a multiple of the alignment of the element that requires the highestalignment. Many compilers have options to change the default alignments.
Differences in structure member alignment will cause incompatibility between different
programs or modules accessing the same data and when data are stored in binary files.
The programmer can avoid such compatibility problems by ordering the structure members
so that no unused bytes need to be inserted. Likewise, the padding at the end of thestructure may be specified explicitly by inserting dummy members of the required size. The
size of the virtual table pointer, if any, must be taken into account (see chapter 11).

5 Stack alignment
The stack pointer must be aligned by the stack word size at all times. Some systems requirea higher alignment.
The Gnu compiler version 3.x and later for 32-bit Linux and Mac OS X makes the stack
pointer aligned by 16 at every function call instruction. Consequently it can rely on ESP = 12
modulo 16 at every function entry. This alignment is not consistently implemented. It is
specified in the Mac OS ABI, but nowhere else. The stack is not aligned when compilingwith option -Os or -mpreferred-stack-boundary=2, but apparently the Gnu compiler
erroneously relies on the stack being aligned by 16 despite these options. The Intel compiler(v. 9.1.038) for 32 bit Linux does not have the same alignment. (I have submitted bug
reports to Gnu and Intel about this in 2006. In 2009 Intel added a -falign-stack=assume-16-byte option to ICC version 11.0 to fix the problem).
The stack is aligned by 4 in 32-bit Windows.
The 64 bit systems keep the stack aligned by 16. The stack word size is 8 bytes, but thestack must be aligned by 16 before any call instruction. Consequently, the value of the stack9

pointer is always 8 modulo 16 at the entry of a procedure. A procedure must subtract an
odd multiple of 8 from the stack pointer before any call instruction. A procedure can rely onthese rules when storing XMM data that require 16-byte alignment. This applies to all 64 bit
systems (Windows, Linux, BSD).
Where at least one function parameter of type __m256 is transferred on the stack, Unix
systems (32 and 64 bit) align the parameter by 32 and the called function can rely on thestack being aligned by 32 before the call (i.e. the stack pointer is 32 minus the word size
modulo 32 at the function entry). This does not apply if the parameter is transferred in aregister.
Various methods for aligning the stack are described in Intel's application note AP 589"Software Conventions for Streaming SIMD Extensions", "Data Alignment and Programming
Issues for the Streaming SIMD Extensions with the Intel® C/C++ Compiler", and "IA-32 Intel® Architecture Optimization Reference Manual".

6 Register usage
Table 4. Register usage

scratchregisters

callee-saveregisters

16 bitDOS,
Windows

32 bitWindows

AX, BX, CX,
DX, ES,
ST(0)-ST(7)EAX, ECX,
EDX,
ST(0)ST(7),XMM0-XMM7,
YMM0-YMM7,
ZMM0-ZMM7,
K0-K7

SI, DI, BP,DS

EBX, ESI,EDI, EBP

32 bitLinux,
BSD, MacOS
EAX, ECX,
EDX,
ST(0)ST(7),XMM0-XMM7,
YMM0-YMM7,
ZMM0-ZMM7,
K0-K7

EBX, ESI,EDI, EBP

registersforparametertransfer

see table 5

see table 5

see table 5

registers
for return

AX, DX,
ST(0)EAX, EDX,
ST(0),
XMM0, YMM0,
ZMM0

EAX,
ST(0),
XMM0, YMM0,
ZMM0

10

64 bitWindows

RAX, RCX,
RDX, R8-R11,
ST(0)ST(7),K0-K7,
XMM0-XMM5,
All YMM/ZMM

registers
except thelower 128
bits of XMM6XMM15
RBX, RSI,
RDI, RBP,
R12-R15,
XMM6-XMM15,

but nothing
beyond thelower 128
bits of vector
registers
RCX, RDX,
R8, R9,XMM0-XMM3,
YMM0-YMM3,
ZMM0-ZMM3
RAX, ST(0),XMM0, YMM0,ZMM0

64 bitLinux,
BSD, MacOS
RAX, RCX,
RDX, RSI,RDI,
R8-R11,
ST(0)ST(7)K0-K7,
XMM0XMM15,
YMM0-YMM15
ZMM0-ZMM31
RBX, RBP,
R12-R15

RDI, RSI,
RDX, RCX,
R8, R9,XMM0-XMM7,
YMM0-YMM7,
ZMM0-ZMM7
RAX, RDX,
ST(0),
XMM0, YMM0,ZMM0

The rules for register usage depend on the operating system, as shown in table 4. Scratch
registers are registers that can be used for temporary storage without restrictions (alsocalled caller-save or volatile registers). Callee-save registers are registers that you have tosave before using them and restore after using them (also called non-volatile registers). You
can rely on these registers having the same value after a call as before the call. For
example, a function using EBP may look like thisFunctionUsingEBP PROC NEAR
push
ebp
mov
ebp, esp
subesp, 52...
mov
eax, [ebp+8]
push
eax
call
AnotherFunction
movesp, ebp
pop
ebp
ret
FunctionUsingEBP ENDP

Here, EBP is saved on the stack in the beginning of the function and restored in the end. The
code relies on EBP being unchanged after the call to AnotherFunction. EAX is also used,
but doesn't have to be saved.
It is more efficient to use registers for transferring parameters to a function and for receiving
the return value than to store these values on the stack. Some calling conventions use
certain registers for parameter transfer, but the rules for which registers to use are compilerspecific in 16-bit and 32-bit systems. In 64-bit systems, the use of registers for parametertransfer is standardized. All systems use registers for return values if the returned object fits
into the registers that are assigned for this purpose. See the next chapter for details.

Segment registers
You only have to care about segment registers in 16-bit mode. DS has to be saved andrestored if you change it. ES can be changed freely. In DOS programs, ES can have any
value. In 16-bit Windows, ES can only have values that are valid segment descriptors. It is
not allowed to use ES for other purposes.
In 32-bit and 64-bit mode, it is not allowed to change any segment register, not eventemporarily. CS, DS, ES and SS all point to the flat segment group. FS is used for a thread
environment block in Windows and for thread specific data in Linux. GS is used for aprocessor control region in 64-bit Windows. It is unused but reserved in 32-bit Windows. It is
probably unused in 32-bit Linux.

Arithmetic flags
The rules for the arithmetic flags (zero flag, carry flag, etc.) are the same as for scratch
registers. These flags need not be saved. Some programming languages (not C++) use thecarry flag for Boolean returns.

Direction flag
The rules for the direction flag is the same in all systems. The direction flag is cleared bydefault. If the direction flag is set, then it must be cleared again before any call or return.
Some compilers and subroutine libraries rely on the direction flag always being clear(Microsoft, Watcom, Digital Mars) while other systems use the double-safe strategy ofalways leaving the direction flag cleared, but not relying on receiving it cleared (Borland,
Gnu).
There is a slight possibility that some programmers may have ignored the rule for the
direction flag. Therefore, it may be wise to use the double-safe strategy and clear the11

direction flag before using it if the code will be linked together with modules from unreliable
sources.

Interrupt flag
It is not allowed to turn off the interrupt flag in programs running in multi-user systems
because this would make it possible to steal unlimited amounts of CPU time from otherprocesses. It may be possible to turn off the interrupt flag in console mode programs
running under Windows 98 and earlier operating systems without network. But sinceprograms written for old operating systems are likely to be run under newer operating
systems, it is reasonable to say that it is never possible to turn off the interrupt flag inapplication programs.

Floating point registers
The floating point registers ST(0)-ST(7) need not be saved. The register stack must be
emptied before any call or return, except for registers used for return values. The 64-bit
Microsoft compiler does not use ST(0)-ST(7).

MMX registers
The MM0-MM7 registers are aliased on the lower 64 bits of the floating point x87 registers
ST(0)-ST(7). There is no callee save rule, so the MMX registers can be used freely in afunction that doesn't use the floating point registers. The register set must be left in x87
mode. Therefore, it is required to issue an EMMS instruction (or FEMMS) before calling anyother (ABI compliant) function and before returning. Unfortunately, not all compilers do so.
Therefore, the use of MMX registers and the __m64 type should be avoided if possible. The
64-bit Microsoft compiler does not use MM0-MM7.

Floating point control word and MXCSR register
The floating point control word and bit 6-15 of the MXCSR register must be saved andrestored before any call or return by any procedure that needs to modify them, except forprocedures that have the purpose of changing these.

Deviating from the conventions
It is possible to deviate from the register usage conventions in an isolated section of code
as long as all interfaces to other parts of the code conform to the conventions. Somecompilers do this in a process known as whole program optimization. Any deviation from theconventions must be well documented. Deviations from good programming practice are
justified only if a significant gain in speed can be obtained.

ABI for 64 bit Windows has been changed
Early versions of the 64 bit Windows ABI specified that only the lower 64 bits of XMM6-XMM15
have callee-save status while later versions specify that all 128 bits must be saved. An
MSDN document dated June 14, 2004 specifies the now-obsolete rule while a later version
dated February 18, 2005 specifies the new rule without comments on the change. Thechange is mentioned in Intel compiler manuals. The 2005 standard is supported by IntelC++ compiler version 8.1.015 and later. My tests show that Microsoft compiler version
14.00.2228.2 uses the obsolete convention, while version 14.00.40310.41 uses the newconvention. I have no information about Microsoft compiler versions between these two
numbers.

Microsoft 16-bit compiler
The 16-bit Microsoft compiler returns float and double through a static memory location
pointed to by AX. long double is returned in ST(0).

12Watcom compiler
The Watcom compiler doesn't conform to the register usage conventions in table 4. The
only scratch register is EAX. All other general purpose registers are callee-save, except for
EBX, ECX, EDX when used for parameter transfer, and ESI when used for return pointer. (In16-bit mode, ES is also a scratch register). It is possible to specify any other register usage
by the use of pragmas in the Watcom compiler.

How many registers should be callee-save?
I have never seen a study of the optimal ratio of caller-save to callee-save registers. Scratch
registers are preferred for temporary values that do not have to be saved across a function
call. Functions that do not call any other functions (leaf functions) and functions that have a
low probability of calling other functions (effective leaf functions) will prefer to use scratch
registers. If a function has more than one call to other functions or calls another function
inside a loop, and if it needs to store values of local variables across these function calls,
then the function becomes simpler by using callee-save registers. If the called functions
need to use the same registers, then there is no advantage in speed, but possibly in size. If
the called functions can use other registers, then there is an advantage in speed as well.
Since leaf functions are the most likely ones to be speed-critical, it is reasonable to have as
many scratch registers as are typically needed in a leaf function. Functions that call otherfunctions, on the other hand, are likely to have more variables and thus need moreregisters. Balancing these considerations, I would expect the optimal fraction of scratch
registers to be between a half and two thirds for architectures that have few registers, andsomewhat lower if there are plenty of registers.
Some compilers have capabilities for whole-program-optimization, and we can expect suchfeatures to become more common in the future. If the compiler has information about theregister needs of both caller and callee at the same time, then it can allocate different
registers to the two functions so that no registers need to be saved. In this case, the optimal
solution is to define callee-save registers only for system functions, device drivers andlibrary functions.
The size of vector registers will be increased to 512 bits in the future AVX-512 instruction
set, and probably increased later to 1024 or 2048 bits. These extensions will use automaticzero-extension of the 256-bit YMM registers. It is therefore not useful to have callee-savestatus for registers that can be expected to be bigger in future instruction sets if compatibility
with existing code is needed.

6.1 Can x87 floating point registers be used in 64-bit Windows?
There was originally some confusion about whether 64-bit Windows allows the use of thefloating point registers ST(0)-ST(7) and the MM0 - MM7 registers that are aliased uponthese. One early technical document found at Microsoft's website says "x87/MMX registers
are unavailable to Native Windows64 applications" (Rich Brunner: Technical Details Of
Microsoft® Windows® For The AMD64 Platform, Dec. 2003). An AMD document says: "64bit Microsoft Windows does not strongly support MMX and 3Dnow! instruction sets in the
64-bit native mode" (Porting and Optimizing Multimedia Codecs for AMD64 architecture on
Microsoft® Windows®, July 21, 2004). A document in Microsoft's MSDN says: "A caller
must also handle the following issues when calling a callee: [...] Legacy Floating-Point
Support: The MMX and floating-point stack registers (MM0-MM7/ST0-ST7) are volatile. Thatis, these legacy floating-point stack registers do not have their state preserved acrosscontext switches" (MSDN: Kernel-Mode Driver Architecture: Windows DDK: Other Calling
Convention Process Issues. Preliminary, June 14, 2004; February 18, 2005). This
description is nonsense because it confuses saving registers across function calls andsaving registers across context switches. Some versions of the Microsoft assembler ml64
(e.g. v. 8.00.40310) gives the following message when attempts are made to use floating
point registers in 64 bit mode: "error A2222: x87 and MMX instructions disallowed; legacy
FP state not saved in Win64".
13However, a public discussion forum quotes the following answers from Microsoft engineers
regarding this issue: "From: Program Manager in Visual C++ Group, Sent: Thursday, May
26, 2005 10:38 AM. It does preserve the state. It's the DDK page that has stale information,
which I've requested it to be changed. Let them know that the OS does preserve state ofx87 and MMX registers on context switches." and "From: Software Engineer in Windows
Kernel Group, Sent: Thursday, May 26, 2005 11:06 AM. For user threads the state of legacy
floating point is preserved at context switch. But it is not true for kernel threads. Kernel
mode drivers can not use legacy floating point instructions."(www.planetamd64.com/index.php?showtopic=3458&st=100).
The issue has finally been resolved with the long overdue publication of a more detailed ABI
for x64 Windows in the form of a document entitled "x64 Software Conventions", well hiddenin the bin directory (not the help directory) of some compiler packages. This document says:"The MMX and floating-point stack registers (MM0-MM7/ST0-ST7) are preserved acrosscontext switches. There is no explicit calling convention for these registers. The use of
these registers is strictly prohibited in kernel mode code." The same text has later appearedat the Microsoft website (msdn2.microsoft.com/en-us/library/a32tsf7t(VS.80).aspx).
My tests indicate that these registers are saved correctly during task switches and thread
switches in 64-bit mode, even in an early beta version of x64 Windows.
The Microsoft C++ compiler version 14.0 never uses these registers in 64-bit mode, anddoesn't support long double precision. The Intel C++ compiler for x64 Windows supports
long double precision and __m64 in version 9.0 and later, while earlier versions do not.
The conclusion is that it is safe to use floating point registers and MMX registers in 64-bit
Windows, except in kernel mode drivers.

6.2 YMM vector registers
The 128-bit XMM registers are extended to 256-bit YMM registers in the AVX instruction
set. The use of YMM registers is supported in Windows 7, Windows Server 2008 R2 andLinux kernel version 2.6.30 and later.
A preliminary ABI published by Intel (see literature p. 59) is supported by operating systems
and compilers. The YMM registers do not have callee-save status, except for the lower halfof YMM6-YMM15 in 64-bit Windows, where XMM6-XMM15 have callee-save status. Noneof the vector registers have callee save status in Linux.
The corresponding vector types are named __m256, __m256d, __m256i. These should
preferably be aligned by 32, but some systems allow alignment by 16. The System V ABI for
64-bit Unix systems requires alignment by 32. The System V ABI for 32-bit Unix does not
mention __m256, but tests show that it is aligned by 32. Apparently, Windows allows
alignment by 16. In both Windows and Linux, these registers are aligned by 32 whentransferred on the stack as function parameters.

6.3 Transitions between VEX and non-VEX code
All instructions with 128-bit vector registers have two versions: a legacy version that leaves
the bits beyond 128 unchanged, and a version with VEX prefix that sets the remaining bits
to zero if the vector register has more than 128 bits. The first Intel processors with 256-bit
vectors had different states where the 256-bit registers were split into two halves when
executing legacy 128-bit instructions, and merged into full 256-bit registers when executing
256-bit instructions. These state transitions were quite costly (70 clock cycles). A
recommended way to avoid the cost of these state transitions was to issue the instruction
VZEROUPPER to clear the upper half of all vector registers or VZEROALL to clear the whole14

registers. Good performance requires that a VZEROUPPER instruction is used when leaving
any code that uses 256-bit or 512-bit vectors if there is any risk that the subsequent code
will use non-VEX 128-bit instructions.
The recommendation from Intel is that any function that uses YMM or ZMM registers should
issue the instruction VZEROUPPER or VZEROALL before calling any ABI compliant function andbefore returning to any ABI compliant function. VZEROUPPER is used if the ABI specifies thatsome of the XMM registers must be preserved (64-bit Windows) or if an XMM register isused for parameter transfer or return value. VZEROALL can optionally be used instead of
VZEROUPPER in other cases. Neither VZEROUPPER nor VZEROALL is needed before calling afunction that uses YMM or ZMM registers for parameter transfer or before returning from afunction that uses the YMM0 or ZMM0 register for return value. Failure to use VZEROUPPER or
VZEROALL will result in poor performance but no error. See manual 2: "Optimizing
subroutines in assembly language" for an explanation, and the discussion in Intel's Forum:
https://software.intel.com/en-us/forums/intel-isa-extensions/topic/301853
The high cost of transition between VEX and non-VEX states is found in Intel Sandy Bridge,
Ivy Bridge, Haswell, and Broadwell processors. The Skylake processor also has different
states, but the state transitions are fast. Any instruction that touches an YMM or ZMM
register will set the Skylake processor in a state where the vector registers are regarded ashaving a dirty upper half. Any non-VEX instruction that writes to an XMM register on the
Skylake will have a false dependence on the previous value of this register. This can cause
a performance loss if there is no VZEROUPPER after VEX code on the Skylake and probably
on later Intel processors as well.
Unfortunately, the first Intel processor with 512-bit registers, called Knights Landing, hasvery inefficient VZEROUPPER and VZEROALL instructions. The Knights Landing processor has
no false dependence when mixing VEX and non-VEX code. The recommendation for the
Knights Landing is not to use VZEROUPPER or VZEROALL. (Intel 64 and IA-32 Architectures
Optimization Reference Manual, 2016). This requires a separate code version for Knights
Landing.
The Skylake, and supposedly also future Intel processors with AVX512, are treating the newregisters zmm16-zmm31 separately so that you can avoid the need for VZEROUPPER by
using only zmm16-zmm31, and not zmm0-zmm15. See the discussion on
https://software.intel.com/en-us/forums/intel-isa-extensions/topic/704023.
Current AMD processors have no such problems, and VZEROUPPER is not needed on any
currently known AMD processors, but it is likely that it will be needed on future AMD
processors.

6.4 ZMM vector registers
The size of vector registers is 512 bits in the AVX512F instruction set, and it is possible that
it will be increased to 1024 bits or more in some future processors.
The AVX512 instruction set increases the number of vector registers in 64-bit mode to 32
registers named ZMM0 - ZMM31. In 32-bit mode, there are only 8 ZMM registers. The 512bit ZMM registers are stored to memory locations aligned by 64, according to the ABI’s,
although unaligned access is possible.
In addition, there are eight new mask registers named k0 - k7. These registers are specified
as 64 bits. Only 16 bits are used in AVX512F, while all 64 bits are used in AVX512BW.
None of the mask registers have callee save status in Linux or Windows. The AVX512F
instruction set has no instruction for storing all 64 bits of a mask register. Therefore, it is15

impossible to use these registers in an interrupt handler under AVX512F in a way that iscompatible with AVX512BW, unless the entire register state is saved.
The mask registers are treated as integers in function calls. Integer registers are used whenmask registers are specified as function parameters or return.
The Intel memory protection instructions, MPX, adds another four new registers, BND0BND3 of 2x64 bits each.

6.5 Register usage in kernel code
Register use is more restricted in device drivers and kernel code than in application code.
The operating system may save time by not saving all registers during interrupts and task
switches.
The FXSAVE and FXRSTOR instructions can save the x87, MMX and XMM registers during atask switch, but not the YMM or ZMM registers. Instead, it is necessary to use the XSAVEand XRESTOR instructions for saving the YMM/ZMM registers and future larger registers
during a task switch. It is not sufficient to store each vector register individually because thiswould be incompatible with future extensions of the register size. Any instruction that writes
to a YMM/ZMM register will clear all bits beyond 256/512 in future register extensions larger
than 256/512 bits. Using XSAVE and XRESTOR is the only way of saving the vector registers
that is compatible with future extensions. The operating system must use CPUID todetermine the necessary size of the save buffer.

Interrupt service routines under Windows and LinuxInterrupt service routines should be fast. It would take too much time to save and restore all
registers in an interrupt service routine. The use of x87 and vector registers is prohibited ininterrupt service routines in most operating systems, including Linux and 32-bit Windows. It
may be possible to use the XMM registers, but not the YMM registers, in interrupt service
routines in 64-bit Windows, but it is not recommended to use XMM registers here becauseof the extra cost of changing the YMM register state.

Device drivers under Windows
The x87 floating point registers can be used in device drivers in 32-bit Windows if saved andrestored with KeSaveFloatingPointState and KeRestoreFloatingPointState. It is strictly
prohibited to use x87 registers and MMX registers in 64-bit Windows device drivers.
XMM registers can be used in Windows device drivers. In 32-bit Windows it is necessary tosave these registers using KeSaveFloatingPointState and KeRestoreFloatingPointState or
KeSaveExtendedProcessorState and KeRestoreExtendedProcessorState. In 64-bit Windows
device drivers it is sufficient to obey the general register usage rules when using XMM
registers.
YMM registers can be used in 32-bit and 64-bit Windows device drivers if saved andrestored with KeSaveExtendedProcessorState and KeRestoreExtendedProcessorState. These
functions will allocate a buffer of sufficient size in case of future register extensions.

Device drivers under LinuxLinux systems use lazy saving of floating point registers and vector registers. This meansthat these registers are not saved and restored on every task switch. Instead they are
saved/restored on the first access after a task switch. This method saves time in case no
more than one thread uses these registers. The lazy saving scheme is not supported inkernel mode. Any device driver that attempts to use these registers improperly will cause an
exception that will probably make the system crash. A device driver that needs to use vector
registers must first save these registers by calling the function kernel_fpu_begin() and16

restore the registers by calling kernel_fpu_end() before returning or sleeping. These
functions also prevent pre-emptive interruption of the device driver which could otherwise
mess up the registers. kernel_fpu_begin() saves all floating point registers and vector
registers if available.
There is no red zone in 64-bit Linux kernel mode.
The programmer should be aware of these restrictions if calling any other library than thesystem kernel libraries from a device driver.

7 Function calling conventions
Table 5. Function calling conventions
segment
word
size
16 bit32 bitcalling convention, operating
system, compiler

parametersin registers

fastcall Microsoft

ax, dx, bx

parameterorder onstack
CPascalPascal(non-member)fastcall Microsoft(member function)ax, dxPascalfastcall Borlandax, dx, bx

Pascalfunction

Watcomax, dx, bx, cx

CCC
PascalC

functioncallerfunctionfunction
hybridcdecl
pascalcdecl
stdcallpascalGnu

commentsfunction

this on stack low

fastcall Microsoft

ecx, edx

Cfunctionfastcall Gnu

ecx, edx
eax, edx, ecx
ecx

CPascalC

functionfunctionfunction

eax, edx,
ebx, ecx
rcx/zmm0,
rdx/zmm1,
r8/zmm2,
r9/zmm3C

functionC

callerrdi, rsi,
rdx, rcx, r8,
r9, zmm0-7

C

callerfastcall Borland
thiscall Microsoft

Watcom64 bitstack
cleanupbycallerfunctionfunction

Windows(Microsoft, Intel)

Linux, BSD, Mac(Gnu, Intel)

17

return pointer in bx

address.
return pointer in ax
this on stack low
address.
return ptr on stack highaddr.
return pointer in si

Stack possibly aligned by
16. See p. 9
return pointer on stack if
not member function

default for member
functions
return pointer in esi
Stack aligned by 16.
32 bytes shadow space
on stack. The specified
registers can only be
used for parameter
number 1, 2, 3 and 4,
respectively.
Stack aligned by 16.
Red zone below stack.

The way of transferring parameters to a function is not always as well standardized as wewould wish, as table 5 shows. In many cases it is possible to specify a particular calling
convention in a C++ declaration, for example:
int __stdcall SomeFunction (float a);

In 16 bit and 32 bit mode, we have the same calling conventions in different operating
systems, but some differences between different brands of compilers, especially for the__fastcall convention and for member functions. In 64 bit mode, the different operating
systems use different calling conventions, but I would not expect differences between
different compilers because all details are defined in the official ABI's.
The entries in table 5 need some explanations. Segment word size defines the hardware
platform. 16 bit refers to DOS and Windows 3.x and earlier. 32 bit refers to Windows 95 andlater, Linux and BSD for the 32-bit x86 processors. 64 bit refers to Windows, Linux and BSD
for the x64 processor architecture.
Calling convention is the name of the calling convention. __cdecl, __stdcall, __pascal and__fastcall can be specified explicitly in C++ function declarations for compilers that support
these conventions. __cdecl is the default for applications and static libraries. __stdcall isthe default for system calls (including Windows API calls) and recommended for library
DLL's in 32-bit Windows. __thiscall is used by default in Microsoft compilers for member
functions in 16 and 32 bit mode. Microsoft, Borland, Watcom and Gnu are brands ofcompilers. Intel compilers for Windows are compatible with Microsoft. Intel compilers forLinux are compatible with Gnu. Symantec, Digital Mars and Codeplay compilers arecompatible with Microsoft. In 64 bit mode, there is one default calling convention for each
operating system, while other calling conventions are rare in 64 bit mode.
Parameters in registers specifies which registers are used for transferring parameters. ecx,
edx means that the first parameter goes into ecx, the second parameter goes into edx, andsubsequent parameters are stored on the stack. Parameter types that do not fit into theregisters are stored on the stack. In general, all integer types, bool, enum and pointers canbe transferred in the general purpose registers. References are treated as identical topointers in all respects. Arrays are transferred as pointers. Float and double types aretransferred in XMM registers in 64 bit mode, otherwise on the stack. Long doubles,
structures, classes and unions may be transferred on the stack or through pointers if they
do not fit into registers. The rules for deciding whether an object is transferred in registers,on the stack, or through a pointer are explained below. Where no register is specified intable 5, all parameters go on the stack. Return parameters are returned in registers as
specified in chapter 6. Composite objects are returned as specified below.
Parameter order on stack. The Pascal order means that the first parameter has the highest
address on the stack and the last parameter has the lowest address, immediately above thereturn address. If parameters are put on the stack by push instructions then the firstparameter is pushed first because the stack grows downwards. The C order is opposite:
The first parameter has the lowest address, immediately above the return address, and thelast parameter has the highest address. This method was introduced with the C language inorder to make it possible to call a function with a variable number of parameters, such as
printf.
Each parameter must take a whole number of stack entries. If a parameter is smaller than
the stack word size then the rest of that stack entry is unused. Likewise, if a parameter istransferred in a register that is too big, then the rest of that register is unused.
If the type of a parameter is not specified explicitly because the function has no prototype or
because it has varargs (...), then parameters of type float are converted to double, charand short int are converted to int.
Stack cleanup by. Specifies whether the stack space used by parameters is freed by thecaller or by the called function. If n bytes of stack space is used for parameters and the18called function has the responsibility for stack cleanup, then this function must return with a
ret n instruction, otherwise ret 0. The 32-bit Gnu compiler uses a hybrid of these two
methods: An object return pointer (see below) must be removed from the stack by the called
function, all other parameters are removed by the caller.
If stack cleanup is the responsibility of the caller, and if speed is important, then it may be
advantageous for the caller to leave the stack pointer where it is after the call and put
parameters for a subsequent function call on the stack by mov instructions rather than bypush instructions.

Further rules
Member functions (Applies to all C++ compilers and operating systems). All member
functions receive a pointer to the object as an implicit parameter, known as this in C++.
This pointer comes before the explicit parameters, usually as the first parameter.
Constructors must return this in the return register.
Returning objects (Applies to all compilers and operating systems). Objects that do not fit
into the return registers are returned to a storage space supplied by the caller. The caller
must supply a return pointer as an implicit parameter to the called function if this isnecessary. The same pointer is returned in the return register. The rules for deciding
whether an object is returned in registers or through a return pointer are explained below foreach platform.
A member function that returns an object can have two implicit parameters, a return pointerand a this pointer. In Microsoft compilers and 64 bit Windows, the this pointer is the firstparameter, the return pointer is the second parameter, and all explicit parameters comethereafter. In Borland and Gnu compilers and in 64 bit Linux and BSD, the return pointer isthe first parameter, the this pointer is the second parameter, and all explicit parameters
come thereafter (this order is compatible with C).
Prolog and epilog. Some systems have specific rules for how the function prolog and epilog
should be constructed in order to support stack unwinding. See chapter 9.
64 bit Windows has more rules. The first parameter goes into rcx or xmm0; the second
parameter goes into rdx or xmm1, etc. This means that if the first parameter is a float in xmm0
and the second parameter is an integer, then the latter goes into rdx, while rcx is unused.
The maximum number of parameters that can be transferred in registers is four in total, notfour integers plus four floats.
The caller must reserve 32 bytes of stack space as "shadow space" for register parameters,even if there are no parameters. The 32 bytes of shadow space come immediately after the
return address. Any parameters on the stack come after the 32 empty bytes. The intended
purpose of the shadow space is as a "home address" for the register parameters which thecalled function can use for storing the register parameters in case the registers are used forsomething else. The caller does not need to put anything into the shadow space. Since theshadow space is owned by the called function, it is safe to use these 32 bytes of shadow
space for any purpose by the called function. Even a function without parameters can relyon having 32 bytes of storage space after the return address.
The shadow space is often used by compilers for storing the register parameters. I haven't
seen a compiler using the shadow space for anything else, although it would be perfectlylegal to do so.
If the type of a parameter is not specified explicitly because the function has no prototype or
because it has varargs (...), and a parameter of type double is passed in an XMM register(float is converted to double), then the corresponding integer register must contain thesame value (not converted to int). This does not apply to parameters passed on the stack.
19

64 bit Linux, BSD and Mac. This system has six integer registers and eight XMM registers
for parameter transfer. This means that a maximum of 14 parameters can be transferred inregisters in 64 bit Linux, BSD and Mac, while 64 bit Windows allows only 4. There is no
shadow space on the stack. Instead there is a "red zone" below the stack pointer that canbe used for temporary storage. The red zone is the space from [rsp-128] to [rsp-8]. A
function can rely on this space being untouched by interrupt and exception handlers (except
in kernel code). It is therefore safe to use this space for temporary storage as long as you
don't do any push or call instructions. Everything stored in the red zone is destroyed byfunction calls. The red zone is not available in Windows.
If the type of a parameter is not specified explicitly because the function has no prototype or
because it has varargs (...), then rax must indicate the number of XMM registers used forparameter transfer. Valid values are 0 - 8. A value of rax that is higher than the actual
number of XMM registers used is allowed as long as it doesn't exceed 8.
sysenter calls use r10 instead of rcx for parameter transfer and rax for function number.

Hot patching support
Hot patching is a mechanism in Windows that allows any function to be replaced by asecurity patch without restarting the process that uses the function. If support for hot
patching is desired then there must be at least 6 unused bytes before the function entry,
and the first instruction in the function must be at least two bytes long. In 32-bit Windows,
the compiler may insert a 2-bytes NOP (MOV EDI,EDI) in the beginning of the function. In
64-bit Windows the compiler inserts a REX.W prefix before the first instruction if it is a push
instruction to make it two bytes long.

7.1 Passing and returning objects
Table 6. Methods for passing structure, class and union objects
16 bit32 bit64 bitfastcalldefault

Linux, BSD, Mac

default

Windows

fastcallWatcomdefault

Gnu v.3 or later

all

BorlandMicrosoft

max number of integer registers
used for transfer of an object
max number of XMM registers
used for transfer of an object
simple structure, class or union
size not a power of 2
contains mixed int and f.p.
contains long double
has member function

0

0

2

0

0

1

0

1

1

1

2

0

0

0

0

0

0

0

0

0

0

2

S
S
S
S
S

S
S
S
S
S

I
S
S
S
I

S
S
S
S
S

S
S
S
S
S

I
S
S
S
I

S
S
S
S
S

I
S
S
S
I

I
S
S
S
I

IZ
PI
IZ
IZ
IZ

R
R
R
S
R

20

Borland

Watcomall

Borlandcalling convention

all

Microsoft

segment word size
compilerhas constructor
S
S
I
S
S
S
S
I
I
IZ
R
has copy constructor
S
S
PI S
S
S
PS PI PI PI PI
has destructor
S
S
PI S
S
I
PS PI PI IZ
PI
has virtual
S
S
PI S
S
S
PS PI PI PI PI
has inheritance
S
S
I
S
S
I
S
I
I
IZ
R
S
has no data
S
S
I
S
S
I
S
I
I
IZ
Symbols:S:
Copy of entire object transferred on the stack.
PI:
Temporary copy referenced by pointer in register. If no vacant register, use PS.
PS:
Temporary copy referenced by pointer on stack.
I:
Entire object transferred in integer registers. Use S if too big or not enough vacantregisters.
IZ:
Entire object transferred in integer register, zero-extended to register size. Use PI if
too big. Use PS if no vacant register.
R:
Entire object is transferred in integer registers and/or XMM registers if the size is nobigger than 128 bits, otherwise on the stack. Each 64-bit part of the object istransferred in an XMM register if it contains only float or double, or in an integer
register if it contains integer types or mixed integer and float. Two consecutive floats
can be packed into the lower half of one XMM register. Consecutive doubles are notpacked. No more than 64 bits of each XMM register is used. Use S if not enoughvacant registers for the entire object. Examples: int and float: RDI, int and double:
EDI and XMM0, four floats: XMM0 and XMM1.
There are several different methods to transfer a parameter to a function if the parameter isa structure, class or union object. A copy of the object is always made, and this copy istransferred to the called function either in registers, on the stack, or by a pointer, as
specified in table 6. The symbols in the table specify which method to use. S takes
precedence over I and R. PI and PS take precedence over all other passing methods.
As table 6 tells, an object cannot be transferred in registers if it is too big or too complex.
For example, an object that has a copy constructor cannot be transferred in registers
because the copy constructor needs an address of the object. The copy constructor iscalled by the caller, not the callee.
Objects passed on the stack are aligned by the stack word size, even if higher alignment
would be desired. Objects passed by pointers are not aligned by any of the compilers
studied, even if alignment is explicitly requested. The 64bit Windows ABI requires that
objects passed by pointers be aligned by 16.
An array is not treated as an object but as a pointer, and no copy of the array is made,except if the array is wrapped into a structure, class or union.
The 64 bit compilers for Linux differ from the ABI (version 0.97) in the following respects:
Objects with inheritance, member functions, or constructors can be passed in registers.
Objects with copy constructor, destructor or virtual are passed by pointers rather than on thestack.
The Intel compilers for Windows are compatible with Microsoft. Intel compilers for Linux arecompatible with Gnu.

21

Table 7. Methods for returning structure, class and union objects(except intrinsic vectors __m64, __m128, __m256, __m512)
16 bit32 bit64 bitLinux, BSD,
Mac

Windows

Mac OS

Gnu except
Mac OS

WatcomBorlandMicrosoft

WatcomBorlandMicrosoft

segment word size
compiler

max number of integer registers
used for returnmax number of ZMM registers
used for returnmax number of f.p. registers
used for returnsimple structure, class or union
bigger than max registers
size not a power of 2
contains only f.p.

0

2

2

2

1

1

2

2

1

2

0

0

0

0

0

0

0

0

0

2

0

0

0

0

0

0

0(1)

0

0

1

P
P
P
P

I
PF
PF
I

I
PSI
PSI
I

I
PS
PS
I

I
P
P
I

I
PSI
PSI
I

I
P
I
I?

I
P
P
I

R
P
R,X
X

contains mixed int and f.p.
contains mixed float and double
contains only one long double

P
P
P

PF
PF
PF

PSI
PSI
PSI

I
PS
I

P
P
P

PSI
PSI
PSI

I
P
P

I
P
I

R
X
F

P

PF

PSI

P
PS

P

PSI

I
P
P
P(F
1)
I
P
P(F
1)
P
P

P
P

P
P

Y
P

P
P
P
P

I
I
PF
PF

I
P
P
P

I
I
P
P

I
I
I
P

I
P
P
P

R
R
R
P

P

PF

P

P

P

P

P

P

has virtual

P

PF

P

P

I
I
I
PA
X
PA
X
PA
X
I

P(I)
P(I)
P(I)
P

has destructor

I
I
I
PA
X
PA
X
PA
X
I

P

P

P

P

has no data
P
I
0I
P(0) P
0
Symbols:I
Returned in integer registers
X
Returned in XMM registers
Y
Returned in XMM0 or YMM0 or ZMM0F
Returned in ST(0) register
F1
If one float, double or long double, use ST(0), otherwise I.
R
The entire object is returned in integer registers RAX and RDX, and/or XMM registers
XMM0 and XMM1, if the size is no bigger than 128 bits, otherwise on the stack. Each64-bit part of the object is transferred in an XMM register if it contains only float or
double, or in an integer register if it contains integer types or mixed integer and float.
Two consecutive float's can be packed into the lower half of one XMM register.
Consecutive double's are not packed. No more than 64 bits of each XMM register isused. Use P if not enough vacant registers. Examples: int and float: RAX, int anddouble: EAX and XMM0, four floats: XMM0 and XMM1.
P
Pointer to temporary memory space passed to function. Pointer may be passed inregister if fastcall or 64-bit mode, otherwise on stack. Same pointer is returned in
AX, EAX or RAX.

I

contains only one SIMD typecontains mixed long double andotherhas member function
has inheritancehas constructor
has copy constructor

22

PS
PF
PAX
PSI
0

Pointer to temporary memory space passed to function. Pointer is passed on stack,even if fastcall. Same pointer is returned in EAX.
Far pointer to temporary memory space passed on stack and returned in DX:AX.
Pointer to temporary memory space passed to function in AX/EAX and returned
unchanged in AX/EAX.
Pointer to temporary memory space passed to function in SI/ESI and returned
unchanged in AX/EAX.
Nothing passed or returned.

A struct, class or union object can be returned from a function in registers only if it issufficiently small and not too complex. If the object is too complex or doesn't fit into theappropriate registers then the caller must supply storage space for the object and pass apointer to this space as a parameter to the function. The pointer can be passed in a registeror on the stack. The same pointer is returned by the function. The detailed rules are given intable 7.
P and PF take precedence over all other. PS takes precedence over all but P. PAX takes
precedence over PSI, which takes precedence over I.
The storage space pointed to by return pointers is aligned by 16 in the 64 bit Gnu compiler
and the 64 bit MS compiler. The 32 bit Microsoft compiler can align this space if explicitly
requested.
The Gnu compiler version 2.x and some implementations of version 3.x differ, as indicatedby the parentheses.
The Intel compilers for Windows are compatible with Microsoft. Intel compilers for Linux arecompatible with Gnu.
The 64 bit Gnu compiler differs from the ABI (version 0.97) by using only one floating point
register for return.

7.2 Passing and returning SIMD types
Table 8. Methods for passing and returning SIMD data types
segment word size
operating system__m64 parameters transferred inregistersalignment of __m64 parameters
on stack__m64 returned in register__m128 parameters transferredin registers
alignment of __m128 parameters
on stack__m128 returned in register__m256 parameters transferredin registers
alignment of __m256 parameters
on stack

32 bitWindows
Linux
3 mmx
3 mmx
registers
registers

4

8

mm0

mm0

64 bitWindows
Linux
4 g. p.
8 xmm
registers
registers(0 in gcc v.
≤ 3.3)
8
8
rax

xmm0

3 xmm
registers
16

3 xmm
registers
16

transferredby pointer
16(mm0 in gcc
v. ≤ 3.3)
8 xmm
registers
16

xmm0

xmm0

xmm0

xmm0

3 ymm
registers
16 or 32

3 ymm
registers
32

transferredby pointer
32

8 ymm
registers
32

23

__m256 returned in register__m512 parameters transferredin registers
alignment of __m512 parameters
on stack__m512 returned in register

ymm0

ymm0

ymm01

ymm0

3 zmm
registers
64

3 zmm
registers
64

transferredby pointer
64

8 zmm
registers
64

zmm0

zmm0

zmm01

zmm0

The types __m64, __m128, __m256 and __m512 define the SIMD data types that fit into the 64bit mmx registers, the 128-bit xmm registers, the 256-bit ymm registers or the 512-bit zmm
registers, respectively. Most compilers supports these types as intrinsic types. There are
special rules for passing and returning function parameters of the these types as shown intable 8. Some compilers have options for either treating these types as intrinsic types, using
the passing methods defined in table 8, or treating them as structures according to the rulesin table 6 and table 7. The types __m128d, __m128i, __m256d, __m256i, __m512d and __m512i
are treated in the same way as __m128, __m256 and __m512.
Under 32-bit Windows and 32-bit Linux, the first three parameters of type __m64 aretransferred in registers MM0 - MM2. Any additional parameters of type __m64 are transferredon the stack aligned by 4. Under 64-bit Linux, __m64 parameters are passed on the stack.
__m64 may not be supported in some 64-bit Windows compilers (see p. 13). Return values oftype __m64 are transferred in RAX in 64-bit Windows, and in MM0 on all other platforms.
Under 32-bit Windows and 32-bit Linux, the first three parameters of type __m128 aretransferred in registers XMM0 - XMM2. Any additional parameters of type __m128 aretransferred on the stack aligned by 16. This alignment is accomplished as follows: If there
are more than three parameters of type __m128 then the stack must be aligned by 16 before
the call instruction. Consequently, the value of the stack pointer is 12 modulo 16 at the entryof the called function. The parameter space on the stack is padded, if necessary, to alignthe parameters of type __m128 by 16. In 64-bit Windows, parameters of type __m128 arepassed by a pointer to an aligned copy. In 64-bit Linux, the first eight parameters of type__m128 are transferred in registers XMM0 - XMM7. Any additional parameters of type __m128
are transferred on the stack aligned by 16. If there are more than eight parameters of type__m128 then the stack space is padded, if necessary, to align the parameters. Return valuesof type __m128 are transferred in XMM0 on all platforms. __m256 and __m512 parameters aretransferred analogously to __m128 parameters, except for the fact that in some systems they
are aligned by 16, in other systems by 32/64, when transferred on the stack.
The __vectorcall convention in Windows allows up to six vector registers to be used forfunction parameters (ZMM0 - ZMM5), and up to four vector registers to be used for function
return. A shadow space of 8 bytes is allocated for each vector register parameter. See
https://docs.microsoft.com/en-us/cpp/cpp/vectorcall for details.

1

Gcc compiler 9.0 has a bug here.

24

8 Name mangling
Name mangling (also called name decoration) is a method used by C++ compilers to add
additional information to the names of functions and objects in object files. This information
is used by linkers when a function or object defined in one module is referenced fromanother module. Name mangling serves the following purposes:
1. Make it possible for linkers to distinguish between different versions of overloadedfunctions.
2. Make it possible for linkers to check that objects and functions are declared inexactly the same way in all modules.
3. Make it possible for linkers to give complete information about the type of unresolved
references in error messages.
Name mangling was invented to fulfill purpose 1. The other purposes are secondary
benefits not fully supported by all compilers.
The minimum information that must be supplied for a function is the name of the function
and the types of all its parameters as well as any class or namespace qualifiers. Possible
additional information includes the return type, calling convention, etc. All this information iscoded into a single ASCII text string which looks cryptic to the human observer. The linker
does not have to know what this code means in order to fulfill purpose 1 and 2. It only needs
to check if strings are identical.
Different C++ compilers use different name mangling schemes. Previously, there was noneed to standardize name mangling because the object files produced by different
compilers were incompatible anyway for other reasons. However, since data representation,
calling conventions, and other details are now being standardized to an increasing degree inthe official ABI (Application Binary Interface) standards of new operating systems, there isgood reason to standardize name mangling schemes as well.
Unfortunately, few compiler vendors have cared to publish the details of their namemangling schemes. This is the reason why I have studied the name mangling schemes ofseveral different C++ compilers and published the detailed results here.
Compiler makers typically use the same name mangling scheme on different hardware
platforms. Though the information given here has been gathered by investigating compilers
for the 16, 32 and 64 bit x86 platforms, it is likely to apply to other platforms as well, andpossibly even to other programming languages. Not all mangling schemes are covered inthis report. There are other schemes used on other platforms, often resembling theschemes described here as Gnu.
The codes used for parameter types, calling conventions, etc. are given in the tables below.
The complete syntax for each compiler is given in the following sections. The syntax iswritten in extended Bacchus Naur notation. For example,<a> ::= <b>

|

[<c>]

[< 𝑑 >]𝑥𝑦

means that syntax element <a> must consist of either syntax element <b> or zero or one
instance of <c> followed by at least x and at most y instances of <d>. Spaces may be
included in the syntax specification for the sake of readability, but the coded string cannot
contain spaces.
The codes for parameter types etc. are given in the tables below. The syntax details aredescribed in the following sections for each name mangling scheme.
25

Table 9. Type codes
type

Microsoft

Borland

WatcomGnu2

Gnu3+
ABI v.3

Gnu4+
ABI v.4+

void
bool
char
signed char
unsigned charshort int
unsigned short int
int
unsigned int
long int
unsigned long int
long long(__int64)
unsigned long long(unsigned __int64)
wchar_t
float
doublelong double_Float16__complex__ float__complex__ double
__m64

X
_N
D
C
E
F
G
H
I
J
K
_J

v
4bool
c
zc
uc
s
us
i
ui
l
ul
j

v
q
a
c
uc
s
us
i
ui
l
ul
z

v
b
c
Sc
Uc
s
Us
i
Ui
l
Ul
x

v
b
c
a
h
s
t
i
j
l
m
x1

v
b
c
a
h
s
t
i
j
l
m
x2

_K

uj

uz

Ux

y1

y1

_W (G)M
N
O, _T, _Z 3

b
f
d
g

w
b
d
t

w
f
d
r

w
f
d
e

Jf
Jd

__m128T__m128@@__m128d

U__m128d@@__m128i

T__m128i@@

Cf
Cd
U8__vectori
5__m64
U8__vectorf
6__m128
U8__vectord
7__m128d
U8__vectorx
7__m128i

w
f
d
e
DF16_
Cf
Cd
Dv2_i

__m128h__m256

T__m256@@__m256d

U__m256d@@__m256i

T__m256i@@__m256h__m512

T__m512@@__m512d

U__m512d@@__m512i

T__m512i@@

T__m64@@

U8__vectorf
6__m256
U8__vectord
7__m256d
U8__vectorx
7__m256i
U8__vectorf
6__m512
U8__vectord
7__m512dU8__vectorx
7__m512i__m512h

Dv4_f
Dv2_d
Dv2_x
Dv8_DF16
Dv8_f
Dv4_d
Dv4_x
Dv16_DF16
Dv16_f
Dv8_d
Dv8_x
Dv32_DF16

varargs ...

Z

e

e

e

z

z

const X
X *const X *volatile X *const volatile X *X * const
X * volatile
X * const volatile
const X * const
X * __restrict
X &X &&const X &volatile X &const volatile X &X[ ] (as global
object)X[][8] (as global
object)X[][16][5] (asglob obj)
X[ ] (as function
parameter)

X
PEAX4
PEBX4
PECX4
PEDX4
QEAX4
REAX4
SEAX4
QEBX4
PEIAX4
AEAX4

xX
pX
pxX5
pwX5
pxwX5
xpX5
wpX5
xwpX5
xpxX5

xX
pnX
pnxX5
pnyX5
pnyxX5
pnX
pnX
pnX
pnxX5

rX

rnX

X
PX
PCX5
PVX5
PCVX5
PX
PX
PX
PCX5
PX
RX

AEBX4
AECX4
AEDX4
PAX4, 6

rxX5
rwX5
rxwX5

rnxX5
rnyX5
rnyxX5
[]X

RCX5
RVX5
RCVX5

X
PX
PKX5
PVX5
PVKX5
PX
PX
PX
PKX5
PX
RX
OX
RKX5
RVX5
RVKX5

X
PX
PKX5
PVX5
PVKX5
PX
PX
PX
PKX5
PX
RX
OX
RKX5
RVX5
RVKX5

PX

PX

PX

PAY07X4,6,7[][8]X

PAY1BA@4X4,6,[][16][5]X

7

QEAX4

pX

pnX

26

const X[] (asfunction param.)X[][8] (as function parameter)
X[][16][5] (asfunction param.)
X near *X far *
X huge *X _seg *X near &X far &
X huge &

QEBX4

xpX

pnxX5

PCX5

PKX

PKX

QEAY07X4,7

pa8$X

pn[8]X

PA7_X

PA8_X

PA8_X

QEAY1BA@4X4,

pa16$a5$X

pn[16][5]X

PA15_A4_X

PA16_A5_X

PA16_A5_X

pX
nX
upX
urX
rX
mX
umX

pnX
pfX
phX

union X
struct X
class X
enum X
enum Y::X

TX@@
UX@@
VX@@
W4X@@
W4X@Y@@<LX>8X<LX>8X<LX>8X<LX>8X<LX+LY+1>8Y
@X

$X$$
$X$$
$X$$
$X$$
$X$:Y$$

G9<LX>8X
G9<LX>8X
G9<LX>8X<LX>8X
Q2<LY>Y<LX>8X<LX>8X<LX>8X<LX>8X<LX>8X
N<LY>Y<LX>8
X<LX>8X<LX>8X<LX>8X<LX>8X
N<LY>Y<LX>8X

X (*Y)(W)10
X Y::*V13
X (Y::*V)(W)15

P6AXW@Z11
PEQY@@X4,14
P8Y@@EAEXW@Z4,16

pqW$X
M<LY>8YX
M<LY>8YqW$X

pn(W)X12
m$Y$$nX12
m$Y$$n(W)X1

PFW_X
PO<LY>8Y_X
PM<LY>YFP<LY>YW_X

PFXWE
M<LY>8YX
M<LY>8YFXWE

PFXWE
M<LY>8YX
M<LY>8YFXWE

7

PAX4
PEX4
PIX4
AAX4
AEX4
AIX4

rnX
rfX
rhX

2

notes:
1
In 64-bit Linux/BSD/Mac, long int and long long is the same, but with different mangling
codes.
3
The implementation of long double in Microsoft compilers has the same precision as
double (64 bits) and uses the code O (capital letter O). A different symbol is used when 80
bits precision is supported. The Intel compiler uses the code _T when 80 bits is used and O
when 64 bits is used. The Symantec/Digital Mars compiler uses the code _Z for 80 bits.
4. The E symbol is a pointer base symbol according to table 13. It is only used in 64 bit
mode. The A, B etc. symbol is the storage class of the target, according to table 10.
5. The letter before X is the storage class of the target, according to table 10. The letter
before p is the storage class of the pointer itself.
6. See page 30 for a comment.
7. After QAY follows: the number of dimensions minus 1, then each dimension except the firstone. These numbers are all coded in the way described in table 18 page 34.
8. <LX> = length of name X, <LY> = length of name Y, as decimal numbers.
9. The G prefix is only used when a union, struct or class appears as a function parameter.
It is not used with pointers or references to these or when the type appears as a templateargument. The G comes before Q2 if the name has a qualifying namespace.
10. Y is a pointer to a function with argument type W and return type X. In the code columns, X
and W represent the codes for types X and W.
11. Replace 6 with 7 if far. A represents the calling convention, using table 16. It may befollowed by a return type modifier code from table 12.
12. Insert any return type modifier or target modifier (table 12) before the return type, and any
member function access code (table 15) before (.
13. V is a pointer to a data member of class Y of type X. In the code columns, X and Y
represent the codes for types X and Y, <LY> represents the length of the name Y.
14. Q qualifies the target. Replace with R if const, S if volatile, T if const volatile.
15. V is a pointer to a function member of class Y with argument type W and return type X. In
the code columns, X ,Y and W represent the codes for types X, Y and W, <LY> represents thelength of the name Y.
16. Replace 8 with 9 if far. A represents a member function access code, using table 15. It isomitted in 16-bit mode. The second E represents the calling convention, using table 16. It
may be followed by a return type modifier code from table 12.
Table 10. Storage class codes
storage class(default)

Microsoft

BorlandA

Watcom
n

27

Gnu2

Gnu3+

near
const
volatile
const volatilefar
const farvolatile far
const volatile far
huge__unaligned__restrict

A
B
C
D
E
F
G
H
I
F
I

n
nx
ny
nyx
f
fx
fy
fyx
h

x
w
xw

C
V
CV

K
V
VK

Example: const int a;
Table 11. Function distance codes
calling distance
near
far

Microsoft

Borland

Y or Q
Z or R

Watcom

Gnu2

Gnu3+

Watcom

Gnu2

Gnu3+

n
f

Example: void far Function1 (int x);
Table 12. Storage class codes for returnstorage classdefault
const
volatile
const volatile

Microsoft

Borland

?A
?B
?C
?D

x
y
yx

Example: const int Function2 (int x);
Table 13. Pointer base codes
pointer base

Microsoft

segment relative (16 and 32 bit mode)
absolute (64 bit mode)__based (64 bit mode)

E
M

Table 14. Member function modifier codes (Microsoft only)
storage or call typeprivateprotected

public

A
B
C
D
E
F

I
J
K
L
M
N

Q
R
S
T
U
V

default
farstaticstatic far
virtualvirtual far

Example: public: virtual int Class1::MemberFunction3 (int x);
Table 15. Member function access codes
storage for this target

Microsoftdefault
const
volatile
const volatile

A
B
C
D

Borlandxw
xw

Watcom

Gnu2

Gnu3+

.x
.y
.yx

Example: int Class1::MemberFunction4 (int x) const;
Table 16. Function calling convention codes
calling convention__cdecl__pascal__fortran__thiscall__stdcall__fastcall__msfastcall__regcall

Microsoft
A17
C
C
E
G
I17

Borland

WatcomGnu2(uppercase)
qf
qs
qr
qm

E

28

@<size>Gnu3+

__vectorcall
interrupt

QA@@<size>qi

Example: int __stdcall Function5 (int x);
notes:
17. In 64-bit mode, this calling convention is coded as A.
Table 17. Operator name codes
operator
constructor X
destructor ~X
operator []operator ()operator ->operator ++X, X++18
operator --X, X--18
operator new
operator new[]operator delete
operator delete[]
operator *X
operator &X
operator +X
operator -X
operator !
operator ~operator ->*operator X * Y
operator /operator %operator X + Y
operator X - Y
operator <<operator >>operator <operator >operator <=operator >=operator ==operator !=operator X & Y
operator |operator ^operator &&operator ||operator =operator *=operator /=operator %=operator +=operator -=operator <<=operator >>=operator &=operator |=operator ^=operator ,operator TYPE()
virtual table

Microsoft
?0
?1
?A
?R
?C
?E
?F
?2
?_U
?3
?_V
?D
?I
?H
?G
?7
?S
?J
?D
?K
?L
?H
?G
?6
?5
?M
?O
?N
?P
?8
?9
?I
?U
?T
?V
?W
?4
?X
?_0
?_1
?Y
?Z
?_3
?_2
?_4
?_5
?_6
?Q
?B
?_7

Borland$bctr$bdtr$bsubs$bcall$barow
$binc
$bdec
$bnew
$bnwa
$bdele
$bdla
$bind
$badr
$badd
$bsub
$bnot
$bcmp
$barwm
$bmul
$bdiv
$bmod
$badd
$bsub
$blsh
$brsh
$blss
$bgtr
$bleq
$bgeq
$beql
$bneq
$band
$bor
$bxor
$bland$blor$basg$brmul$brdiv$brmod$brplu$brmin$brlsh$brrsh$brand$bror$brxor$bcoma$o<L>TYPE20

Watcom
$ct
$dt
$od
$op
$oe
$og
$oh
$nw
$na
$dl
$da
$of
$ok
$oj
$oi
$oc
$oq
$ol
$of
$om
$on
$oj
$oi
$ob
$oa
$rc
$re
$rd
$rf
$ra
$rb
$ok
$os
$or
$ot
$ou
$aa
$ab
$ae
$af
$ac
$ad
$ah
$ag
$ai
$aj
$ak
$oo
$cv

Gnu2
_
_$
__vc_
__cl_
__rf_
__pp_
__mm_
__nw_ 19__vn_19__dl_19__vd_19
__ml_
__ad_
__pl_
__mi_
__nt_
__co_
__rm_
__ml_
__dv_
__md_
__pl_
__mi_
__ls_
__rs_
__lt_
__gt_
__le_
__ge_
__eq_
__ne_
__ad_
__or_
__er_
__aa_
__oo_
__as_
__aml___adv___amd___apl___ami___als___ars___aad___aor___aer___cm___op<L>TYPE_20

Gnu3+
C1,C2
D1
ix
cl
pt
pp
mm
nw
na
dl
da
de
ad
ps
ng
nt
co
pm
ml
dv
rm
pl
mi
ls
rs
lt
gt
le
ge
eq
ne
an
or
eo
aa
oo
aS
mL
dV
rM
pL
mI
lS
rS
aN
oR
eO
cm
cv<L>TYPE20

Example: Class1 operator + (Class1 & a, Class1 & b);notes:
18. X++ is distinguished from ++X by a dummy int parameter.
19. If the operator is not a class member and there are no extra parameters, i.e. if the built-in
operator is replaced, then the full mangled name is replaced by ___builtin_new,___builtin_vec_new, ___builtin_delete, or ___builtin_vec_delete.
20. <L> is the length of the name of TYPE.

29

8.1 Microsoft name mangling
Microsoft compilers use a name mangling syntax that includes all information needed tocheck that an object or function is declared in exactly the same way in all modules (except
for array sizes). It is also designed to be as short as possible, while allowing caseinsensitive linking. The code is unambiguous so that the complete C++ declaration of an
object or function can be recovered from a mangled name. Several other compilers for
Windows use the same or almost the same name mangling scheme.
The public mangled name of a global object is composed according to the following syntax:<public name> ::= ? <name> @ [ < namespace > @]∞0 @ 3 <type> <storage class>

The mangled name of a static class member object is:<public name> ::= ? <name> @ [ < class name > @]1∞ @ 2 <type> <storage class><name> is the case sensitive C++ name of the object.
<namespace> is any namespace surrounding the object.
<class name> is the class the object belongs to or a namespace. Class names andnamespaces are treated as equivalent. In case of nested classes or namespaces, theinnermost class or namespace comes first.
<type> is the code for object type, taken from table 9.
<storage class> is any storage modifier, taken from table 10. The default is A. This code isreplaced by Q1@ for member pointers and member function pointers, regardless of storage

class.
Pointers and references include the <pointer base> and <storage class> code for thetarget. <pointer base> is a pointer base code according to table 13, which is used only in
64-bit mode. Global pointers and references (including function pointers and member
pointers) in 64-bit systems include the <pointer base> twice, both before the <storage
class> code of the target and before the <storage class> code of the pointer or reference
itself. (Early 64-bit C++ compilers didn't have <pointer base> codes).
Examples:int alpha;is coded as?alpha@@3HA
char beta[6] = "Hello";

is coded as?beta@@3PADA
double Class1::gamma[10][5];is coded as?gamma@Class1@@2PAY04NA
int * delta;

is coded in 16-bit and 32-bit systems as?delta@@3PAHA

and in 64-bit systems as?delta@@3PEAHEA

Note that global arrays are coded as pointers (P) while arrays as function parameters arecoded as pointer constants (Q). This should have been opposite, since arrays as function
parameters are equivalent to non-constant pointers, while global arrays are equivalent to30

pointer constants. Apparently, this illogical coding has been retained in almost all compilers
for the sake of compatibility with legacy code. The first 64-bit C++ compilers used _O insteadof P for global arrays, but they soon returned to the P syntax. The consequence of thisillogical coding is that an array in one module can be confused with a pointer with the same
name in another module, while pointers and arrays as function parameters are not treatedas equivalent even though they are equivalent in the C++ syntax.
The mangled name of a global function is composed according to the following syntax:<public name> ::= ? <function name> @ [ < namespace > @]∞0 @ <near far><calling conv> [<stor ret>] <return type> [ < parameter type >]1∞ <term> Z<near far> is Y for near, Z for far. Far calls are only possible in 16-bit mode.
<calling conv> is the calling convention, taken from table 16. The default is A.
<stor ret> defines the storage class of the return, using the codes in table 12. It is omitted
for simple types if the storage class is not const or volatile. It is always included if the
return type is a struct, class or union.
<return type> is the type returned by the function, taken from table 9.

<parameter type> is the type of each function parameter, taken from table 9.
<term> is @ except if the parameter list is void (X) or ends with ... (Z). In these cases, the @is omitted because the list is sure to end here.
Example:void Function1 (int a, int * b);

is coded as?Function1@@YAXHPAH@Z

The mangled name of a class member function is composed according to the following
syntax:<public name> ::= ? <function name> @ [ < class name > @]1∞ @ <modif> [<const vol>]<calling conv> [<stor ret>] <return type> [ < parameter type >]1∞ <term> Z<modif> defines the private, protected, public, static, virtual, near and far modifiers of amember function according to table 14. Far calls are only possible in 16-bit mode.
<const vol> is a member function access code from table 15. The default is A. It is omitted

for static member functions.
The default calling convention for non-static member functions in 16 bit mode is C(__pascal), in 32 bit mode it is E (thiscall). In 64 bit mode the only possible calling
convention is A. The default calling convention for static member functions is A.
Example:int Class1::MemberFunction(int a, int * b);

is coded in 32-bit mode as?MemberFunction@Class1@@QAEHHPAH@Z

and in 64-bit mode as?MemberFunction@Class1@@AEAAHHPEAH@Z

Constructors, destructors, operators and member operators are coded in the same way asfunctions, by replacing <function name>@ with the operator name taken from table 17. The
return type of constructors and destructors is replaced with @.
31

Virtual tables are coded as ??_7[ < class name > @]1∞ @6B@
Template functions and template classes are coded by replacing <function name> or<class name> by ?$ <name> @ [ < template parameter >]1∞
where <name> is the name of the templated function or class. If the template parameter is a
typename or class then <template parameter> is a type as defined in table 9. If thetemplate parameter is a constant, then<template parameter> ::= $0 <integer>
where <integer> is coded as explained in table 18 below.

Abbreviations for repeated names and parameter types
The name mangling scheme includes two means of shortening mangled names that would
contain the same name or type more than once. The first method involves repeated types,
the second method involves repeated names.
Abbreviation of repeated types. This method applies to type declarations in a function
parameter list or function pointer parameter list. Only types that need more than one
character for its code are included in this scheme. This includes pointers, references,arrays, bool, __int64, struct, class, union, and enum parameters. The first such parameterin a parameter list is assigned the number 0, the second such parameter is assigned thenumber 1, and so forth. Simple types that are encoded with a single letter are not assigned
a number. Any repeated instance of a type with an assigned number in the parameter list is
replaced by the number of the first instance. The maximum number is 9. If the number
would exceed 9 then the repeated instance must use the full declaration. The return type is
not included in the type abbreviation scheme.
Example:bool ExampleFunction (int*a, int b, int c, int*d, bool e, bool f, bool*g);

is coded as?ExampleFunction@@YA_NPAHHH0_N1PA_N@Z
Here, the return type bool is coded as _N. int*a is coded as PAH, which is assigned thenumber 0. int b is coded as H, and is not assigned a number because it is coded as asingle letter. int c is also coded as H because single letter codes are not abbreviated. int*dhas the same type as a, and is abbreviated to the number 0. bool e is coded as _N and isassigned the number 1. The previous instance of _N was a return type, so it cannot be
copied. bool f has the same type as e and is replaced by the number 1. The bool inbool*g is not abbreviated because sub-expressions cannot be abbreviated.

If the parameter list contains a function pointer, then the parameter types inside the function
pointer type declaration are included in the abbreviation scheme, both as sources that canbe assigned numbers and as targets that can be abbreviated. The return type in the function
pointer type declaration is not included. If the return type of a function declaration is afunction pointer, then the parameters, but not the return type, of this function pointerdeclaration are included in the type abbreviation scheme of the whole function declaration.
Example:typedef int * (* FunctionPointer) (int * a, int * b);
FunctionPointer WeirdFunction(FunctionPointer x,FunctionPointer y,int*z);

is coded as?WeirdFunction@@YAP6APAHPAH0@ZP6APAH00@Z10@Z
Here, the code for int * is PAH, and the code for FunctionPointer without abbreviation
would be P6APAHPAHPAH@Z. The first occurrence of FunctionPointer is in the return type of
WeirdFunction. Within this occurrence, the first occurrence of PAH is the return type which is
excluded from the abbreviation scheme. The second occurrence of PAH, representing int*a,
is assigned the number 0. The third occurrence of PAH, representing int*b, is replaced by 0.
The second occurrence of FunctionPointer represents parameter x. Within this, the firstoccurrence of PAH is not abbreviated because it represents the return type of32

FunctionPointer. The next two occurrences of PAH, representing a and b in x, are both
replaced by the 0 that has already been assigned. The entire sequence representing
parameter x is thus P6APAH00@Z. This sequence is assigned the number 1. FunctionPointery is simply reduced to 1, and int*z is reduced to 0.

Abbreviation of repeated names. This method applies to any name that appears inside adeclaration, such as structures, classes, unions, enums, and namespaces. If any such
name occurs more than once in a mangled name, then all but the first occurrence will be
replaced by a number, no matter how short the name is. The number will represent a copyof the name, but not its context or meaning. A name can be copied even if the different
occurrences of the name have different meanings (because of namespace or class scope
qualifications). The algorithm is as follows: First eliminate any repeated types using the firstabbreviation method. Any names that have been eliminated by the type abbreviation
method need no further consideration. Then assign numbers to the first occurrence of eachname. The first name, which is usually the function's name (except for constructors,
destructors, operators and template functions), is assigned the number 0, the second nameis 1, and so forth. Each repeated name is then eliminated by replacing <name>@ with thenumber. If the number would be higher than 9 then the name cannot be eliminated.
Example:Class1 * SomeFunction (Class1 * a, Class2 * b, Class2 * c, Class2 & d);is coded as?SomeFunction@@YAPAVClass1@@PAV1@PAVClass2@@1AAV2@@Z
Here, parameters b and c have the same type, so Class2 * c is reduced by the first
method, and simply becomes a 1. The last parameter Class2 & d cannot be reduced by thetype abbreviation method because b and d have different types. Neither can the double
occurrence of the name Class1, because the type abbreviation method doesn't apply toreturn types. The name abbreviation method now assigns the numbers SomeFunction = 0,Class1 = 1, Class2 = 2. Now parameter a can be changed from PAVClass1@@ to PAV1@, andparameter d is changed from AAVClass2@@ to AAV2@.

Templated names and template parameters are isolated from the numbering of names. Thismeans that a name inside a template argument can only be eliminated if there are multiple
occurrences of this name within the same templated name. Likewise, templated names are
isolated from each other, even if they are identical. In case of nested templates, each subtemplate has its own isolated number sequence.
Example:void Class1::MyTemplateFunction<Class1> (Class1*);

will be coded as??$MyTemplateFunction@VClass1@@@Class1@@QAEXPAV0@@Z
Here, the templated name MyTemplateFunction<Class1> is coded as?$MyTemplateFunction@VClass1@@. This template has its own number sequence(MyTemplateFunction = 0, VClass1 = 1), which is isolated from the rest. The first name in therest of the code is the representation of the scope Class1:: coded as Class1@. Thisoccurrence of Class1 gets the number 0. The parameter Class1*, which was first coded as
PAVClass1@@ is now changed to PAV0@, where the 0 refers to the name in Class1::, not thename in <Class1>.

Coding of numbers
Numbers within mangled names are needed for array dimensions, array sizes, and templateparameters. These numbers are coded according to the algorithm in table 18. It appears
that this algorithm was designed to make the coding as short as possible, rather thanmaking it human readable.

33

Table 18. Microsoft number encoding
range for N
1  N  10
N > 10N=0
N<0coding(N - 1) as a decimal number
code N as a hexadecimal number without leading zeroes,
replace the hexadecimal digits 0 - F by the letters A - P, end
with a @A@? followed by ( - N) coded as above

8.2 Borland name mangling
This name mangling scheme is used only by Borland compilers.
The name of a global object without class or namespace qualifiers is not mangled, except
for un underscore prefix:<public name> ::= _ <name>

A global object with class or namespace qualifiers is coded as<public name> ::= [@ < class name >]1∞ @ <name>where <class name> is a class or namespace. In case of nested classes or namespaces, theoutermost comes first.
Functions, member functions, constructors, destructors and operators are all coded
according to the following syntax:<public name> ::= [<template prefix>] [@ < class name >]∞0 @ <name> $ [<const vol>] q[<calling convention>] [ < parameter type >]1∞
<template prefix> is @ if the function is a template function or member of a template class,otherwise nothing.
<const vol> is a member function access code from table 15. It is omitted by default.
<calling convention> defines the calling convention as given in table 16. It is omitted bydefault. There is no distinction between near and far calling.
<parameter type> defines each function parameter, using the codes in table 9. The returnparameter is not coded.
For constructors, destructors and operators, replace <name> by an operator name from table17.
Template functions have no special encoding other than the @ prefix, as the templateparameters are implied by the function parameter types. The Borland compilers I havetested only support such cases of template functions where the template parameters can beinferred from the function parameters.
Template class member functions and member objects are coded by replacing<class name> by% <name> [$t < type code > | $ii$ < value >]1∞ %Global objects of a template class are not mangled if in the global namespace.
34

Virtual tables are encoded as@@<class name>@3

Type codes that appear more than once in the <parameter type> list of a function areabbreviated if the type is a pointer, reference, array, struct, class, union, enum or bool, but
not if it is a simple type with one or two-letter code. All parameters are assigned a number,beginning with 1. The code t1 repeats the first parameter, t2 repeats the second parameter,ta repeats the 10'th parameter, tz repeats parameter number 35. Further parameters
cannot be copied. If the parameter list contains a function pointer, then the list ofparameters for the target function has its own isolated number sequence, so that type codes
within the parameter list of the target function can be abbreviated, but not the return type ofthe target function. There is no method for abbreviating repeated names that are not part ofidentical parameter types.
Examples:char beta[6] = "Hello";

is coded as_beta

double Class1::gamma[10][5];is coded as@Class1@gamma
bool ExampleFunction (int*a, int b, int c, int*d, bool e, bool f, bool*g);

is coded as@ExampleFunction$qpiiit14boolt5p4bool
void TemplateClass<float>::MemberFunction (TemplateClass<float>*);is coded as@@%TemplateClass$tf%@MemberFunction$qp18%TemplateClass$tf%

8.3 Watcom name mangling
This name mangling scheme is used only by Watcom compilers.
The public mangled name of a global object is composed according to the following syntax:<public name> ::= W? <name> $ [ : < namespace > $]∞0 <storage class> <type>where <storage class> is taken from table 10 and <type> is taken from table 9. <namespace>can be any namespace or class qualifier, the innermost first.
Examples:int alpha;is coded as
W?alpha$ni

char beta[6] = "Hello";

is coded as

W?Beta$npna
double Class1::gamma[10][5];is coded as
W?gamma$:Class1$n[][5]dFunctions, member functions, constructors, destructors and operators are coded as follows:<public name> ::= W? <function name> $ [ : < class name > $]1∞ <near far> [<const vol>]( [ < parameter type >]∞0 ) [<stor ret>] <return type>35

<class name> is a class name or namespace. In case of nested classes or namespaces, theinnermost comes first.
<near far> is n for near or f for far. Far calls are only possible in 16 bit mode.
<const vol> is a member access code from table 15. It is omitted by default.
<parameter type> defines the type of each function parameter according to table 9. No<parameter type> is included if the parameter list is (void).
<stor ret> is a return type storage class from table 12. It is omitted by default.
<return type> defines the return type according to table 9.

Example:bool ExampleFunction (int*a, int b, int c, int*d, bool e, bool f, bool*g);

is coded as
W?ExampleFunction$n(pniiipniqqpnq)q

Constructors, destructors and operators are coded by replacing <function name>$ with aname from table 17. The return type of constructors and destructors is replaced by _.
Names that appear more than once in a mangled code are reduced by replacing all but thefirst occurrence of a name by a reference to the first occurrence. The first occurrence ofeach name is assigned a number, starting with 0. A repeated occurrence of a name is thenabbreviated by replacing <name>$ by one of the numbers 0 - 9. No replacement is possible if
a higher number would be needed. A name can be replaced even if the repeatedoccurrence has a different meaning or context. There is no method for abbreviating
repeated types.
Virtual tables have the funny code

<public name> ::= W?$Wvf <nl> o4: <class name> $$nx[]pn()v
where <nl> is the length of the class name + 4, coded as a two-digit base 36 number withdigits 0-9, a-z.

Template classes are coded by replacing <class name>$ by<name>$::[1n < type > | 0 < number >]1∞
where <type> is a template type parameter, and <number> is a template integer
parameter, coded as a base-32 number with digits 0-9, a-v, followed by a suffix z if positive
or zero, and y if negative. Template functions have no special encoding as the templateparameters are implied by the function parameter types. The Watcom compilers I havetested only support such cases of template functions where the template parameters can beinferred from the function parameters.

8.4 Gnu 2 name mangling
This mangling scheme is used in Gnu C++ version 2.x.x under several operating systems(Linux, BSD, Windows). Later versions of Gnu C++ use a different scheme described in thenext section.
The Gnu2 mangling scheme is a dialect of the scheme used by cfront, one of the oldest
C++ tools. Variants of this scheme are widely used in UNIX systems (See: J. R. Levine:
Linkers and Loaders. Morgan Kaufmann Publishers, 2000).
The type of a global object is not coded, only class or namespace qualifiers, if any:
<public name> ::= [_ <qualifiers list> <list term> ] <name>36where<qualifiers list> ::= [<qualifiers count>] [ < name length > < class name >]1∞
<list term> ::= . | $<qualifiers count> is the number of class or namespace qualifiers. It is omitted if the countis 1. It is Q<number> if the number is 2 - 9. It is Q_<number>_ if the number is more than 9.
All numbers are decimal. Some versions use . as list terminator (Red Hat), other versions
use $ (FreeBSD, Cygwin, Mingw32). The namespace std is ignored.
char beta[6] = "Hello";

is coded as
beta
char Namespace1::beta[6];is coded as_10Namespace1.beta or _10Namespace1$beta

Functions and member functions are coded as follows<public name> ::= <name> _ _ [ <qualifiers list> | F ] [ < parameter type >]1∞

The <qualifiers list> is replaced with an F if there are no class or namespace qualifiers.
<parameter type> is the type of each function parameter, as defined by table 9. The return

type and function modifiers are not included.
Types that occur more than once in the parameter list can be repeated according to thefollowing rules. Each parameter is assigned a number, beginning with 0. All parameters arenumbered, regardless of whether they are identical to a previous parameter. A repeatedoccurrence of a parameter is replaced by a reference to the first occurrence if it is a pointer,
reference, array or other non-simple type. bool is also treated as a non-simple type, while
long double and unsigned __int64 are treated as simple types. A repeated occurrence ofa non-simple parameter is replaced by T <first occur> where <first occur> is thenumber assigned to the first occurrence. If the number is bigger than 9 then <first occur>
is followed by an _ . A sequence of identical types can be replaced by N <count> <firstoccur> where <count> is the number of identical parameter types to replace and <firstoccur> is the number assigned to the first occurrence. Both <count> and <first occur>are followed by an _ if bigger than 9. For obscure reasons, the compiler uses the T
replacement rather than the N replacement for the first parameter in a sequence of identicalparameters if the preceding parameter is not the first occurrence of the same type. There isno method for abbreviating repeated names that are not part of identical parameter types.
Example:bool ExampleFunction (int*a, int b, int c, int*d, bool e, bool f, bool*g);

is coded as

ExampleFunction__FPiiiT0bT4Pb

Constructors, destructors and operators are coded in the same way as functions with<name>_ replaced by an operator name from table 17.
Template functions are coded as follows
numtp<public name> ::= <name> _ _ H <numtp>[ Z < type parameter > | < type > < value > ]numtp_ [ <qualifiers list> ] [ < parameter type > | X < temp. par. num > 1]1∞ _ <return type>where <numtp> is the number of template parameters, <type parameter> is a template
type parameter, <value> is a template constant parameter of type <type>. <parametertype> in the list of function parameters is replaced by X <temp. par. num.> 1 if, and only37

if, it is explicitly declared as the same type as a template type parameter. <temp. par.
num.> is the number of the template parameter referred to, starting at 0. The return type isincluded only for template functions.
Template classes are coded by replacing <class name length> <class name> bynumtp

t <name length> <name> <numtp> [ Z < type parameter > | < type > < value > ]numtp

Under Windows, all public names get an additional underscore prefix, for example_ExampleFunction__FPiiiT0bT4Pb

The _ prefix is used only under Windows. It is omitted in Linux and FreeBSD, except
possibly if the old a.out object file format is used.

8.5 Gnu 3 and later name mangling
This mangling scheme is used in Gnu C++ version 3.x.x and later under several operating
systems (Linux, BSD, Mac OS X IE32, Windows) and on several platforms. It is described in"Itanium C++ ABI". The same scheme is used by Intel compilers for Linux and Mac OS.
Different variants are available for the Gnu compiler version 4.x.x, specified by thecommand line parameters -fabi-version=3 and -fabi-version=4, etc. A value
for -fabi-version of 4 or more is preferred when parameters of type __m256 are used. A
value of 0 gives the latest version.
Earlier versions of Gnu C++ use a different scheme described in the previous section.
The name of a global object without class or namespace qualifiers is not decorated in any
way:<public name> ::= <name>

A global object with class or namespace qualifiers is coded as<public name> ::= _Z <qualified name>where<qualified name> ::= N [< simple name >] ∞2 E
<simple name> ::= <name length> <name>where <name length> is the length of each name as a decimal number. In case of nested
classes or namespaces, the outermost comes first. The object name comes last.
Examples:char beta[6] = "Hello";

is coded as
beta

char Namespace1::beta[6];is coded as_ZN10Namespace14betaE

There are special abbreviations if the outermost namespace is std. If std is the only
qualifier, use<qualified name> ::= St <simple name>

If there are more qualifiers, use<qualified name> ::= N St [< simple name >] ∞2 E

38

If std is not the outermost qualifier, then it is treated as any other qualifier, i.e. coded as
3std.
Functions, member functions, constructors, destructors and operators are all coded
according to the following syntax:<public name> ::= _Z <simple or qualified name> [ < parameter type >]1∞
<simple or qualified name> ::= <simple name> | <qualified name> | <operator name><operator name> is an operator name from table 17. Any classes or namespaces come firstin <qualified name> and the function name comes last. The abovementioned abbreviations
for std apply.

Example:bool Example1Function (int a, int * b, bool c, bool d, bool * e);is coded as_Z16Example1FunctioniPibbPb

Virtual tables are coded as<public name> ::= _ZTV <simple or qualified name>Template functions and template classes are coded by replacing <simple name> by<simple name> I [ < template parameter >]1∞ E<template parameter> ::= <type>|

L <type> <value> E

where the first option is for template type parameters and the second option for template
constant parameters.
The return type of a template function is included as the first type in the parameter type list.
If the template function has no parameters, then the code for void (v) is omitted. This isdifferent from non-template functions, where the return parameter is omitted and the void is
included.
There is a method for abbreviating repeated names and types. This abbreviation scheme
does not distinguish between names and types. The first occurrence of each name or nonsimple type is assigned a symbol in the following sequence:
S_, S0_, S1_, ... S9_, SA_, SB_, ... SZ_, S10_, S11_, ...

These abbreviation symbols are assigned, in the order of occurrence, to the first occurrenceof each name of structures, classes, unions, enums and namespaces, but not to the nameof the function or object itself. The abbreviation symbols are also assigned to all non-simple
types occurring anywhere in the mangled name. A non-simple type is any type that needs
more than one character for its encoding, according to table 9. This scheme also assigns
abbreviation symbols to non-simple types that form part of the declaration of a more
complex type. For example, the type Class1** gets three abbreviation symbols, for Class1,
Class1*, and Class1**, respectively. All but the first occurrence of each name or type isreplaced by the abbreviation symbol, even if the abbreviation symbol is longer than theoriginal code. If the same name has more than one meaning because of different class ornamespace qualifiers, then the occurrences with different meanings are treated as different
names.
Template type parameters are included in this abbreviation scheme. A repeated occurrenceof a type in <template parameter> is abbreviated by e.g. S0_. If a function parameter is39

explicitly declared as the same type as a template parameter, then the first occurrence isreplaced by T_, T0_, etc., where T_ refers to the first template parameter. A repeatedoccurrence of the template parameter in the function parameter list is abbreviated using theS_ scheme.
Example:bool Example2Function (int a, int * b, Class1 & c, Class1 d, Class1 & e);

is coded as_Z16Example2FunctioniPiR6Class1S0_S1_

Under 32-bit Windows and 32- and 64-bit Mac OS, all public names get an additional
underscore prefix, for example__Z16Example2FunctioniPiR6Class1S0_S1_

There is a separate name mangling scheme for vector functions. This is defined in the
document Vector Function Application Binary Interface Specification for OpenMP. This isused in the libmvec library.

8.6 Intel name mangling for WindowsIntel compilers for 32 bit and 64 bit Windows use the same name mangling scheme as
Microsoft.
The Intel compiler comes in two versions, a legacy version named “classic”, and a newversion named LLVM-based. The latter version is a forking of the Clang compiler andbehaves very much like the Clang compiler. The following information applies to the“classic” version of the Intel compiler.
The Intel compilers can treat the types __m64 and __m128 as intrinsic types when the/Qmspp- option is specified. In this case it uses _K, which is the code for unsigned __int64,
to represent __m64 and __m128. This prevents function overloading. This option is deprecatedand should be used only when compatibility with legacy code is needed.
Where a function is compiled for automatic CPU dispatching, the following suffixes areappended to the (mangled or unmangled) names of CPU-specific functions in order todistinguish the version for each CPU:
Table 19. Intel CPU-specific function name suffixes
CPU
Generic
Pentium
Pentium Pro
Pentium MMX
Pentium II
Pentium III no XMM
Pentium III
Pentium 4
Pentium M
Pentium 4 w. SSE3
Core 2 duo
Wolfdale
Atom
Nehalem
Nehalem
Sandy Bridge

Instruction set
specified baseline(80386 or higher)
Pentium
CMOV
MMX
CMOV and MMX
CMOV and MMX
SSE
SSE2
SSE2
SSE3
Suppl. SSE3
SSE4.1
SSE3
SSE4.2 + POPCNTPCLMUL + AES
AVXName suffix

40__intel_cpu_indicator

.A

1

.B
.C
.D
.E
.G
.H
.J
.K
.L
.M
.N
.O
.P
.Q
.R

2
4
8
0x10
0x40
0x80
0x200
0x400
0x800
0x10000x20000x40000x80000x10000
0x20000(unused?)(unused?)(unused?)(unused?)Haswell
Skylake
Xeon Phi
MIC-AVX512 KNL?
?
CORE-AVX512
Knights Mill

AVX2+FMA3+BMI1/2
RDSEED, ADX, RTM
AVX512F/PF/CD

.S
.T
.U
.V
.W
.X
.Y?
.Z

0x400000x80000
0x100000
0x200000
0x400000
0x800000
0x2000000
0x4000000
0x10000000

AVX512F/BW/DQ/VL.a.j

The dot (.) is replaced by a $-sign on some platforms. __intel_cpu_indicator is an internalvariable.
Newer versions no longer have a cumulative sequence of added features. The 32-bit
variable __intel_cpu_indicator is replaced by the 64-bit variable__intel_cpu_feature_indicator with one bit for each feature. The name suffixes are stillused. The following bits of __intel_cpu_feature_indicator have been identified:41

Table 20. Intel CPU feature indicator bits
Instruction set
x87
CMOV
MMX
FXSAVE
AES
SSE2
SSE3
SSSE3
SSE4.1
SSE4.2MOVBE
PCLMULAES
F16C
RDRANDFMA (FMA3)
BMI1+BMI2
LZCNT
HLE
RTM
AVX2
AVX512DQ
AVX512FADXRDSEED
AVX512IFMA
AVX512ER
AVX512PF
AVX512CDSHA
MPX
AVX512BW
AVX512VL
AVX512VBMIAVX512-4FMAPSAVX512-4VNNIWAVX512VPOPCNTDQAVX512VBMI2
GFNI
CLWB
RDPID
SGX

__intel_cpu_feature _indicator bit number
0
1
2
3
4
5
6
7
8
9
10
11
13
14
15
17
18
19
20
21
22
23
24
27
28
29
30
32
33
34
35
36
37
38
39
40
41
42
44
45
49
50
53

8.7 Intel name mangling for LinuxIntel compilers for 32 bit and 64 bit Linux and Mac OS use the same name mangling
scheme as Gnu 3.x. In case of CPU dispatching, the suffixes listed above are used.

42

8.8 Symantec and Digital Mars name mangling
The Symantec and Digital Mars C++ compilers use the same name mangling scheme as
Microsoft with very few exceptions. I have found the following differences:•long double has 80 bits precision and is coded as _Z in Symantec/Digital Mars

compilers. In Microsoft compilers, long double has 64 bits precision (same as
double) and is coded as O. Intel compilers use _T for 80 bits precision.
•

The type wchar_t is coded as _Y, while Microsoft compilers use _W.

•

The method for abbreviating types (page 32) applies to bool (_N), but not to othertwo-character codes (_J, _K, _Y, _Z). It does apply to pointers and references to suchtypes.

•

The coding of member function pointers do not have the member function accesscode and return type modifier code. This may be an obsolete syntax, since it is also
missing in 16-bit Microsoft compilers.

•Global arrays have the code Q while arrays as function parameters are coded as
pointers (P) in Symantec and Digital Mars compilers. This is more correct than thecoding generated by Microsoft compilers, as explained on page 30.

8.9 Codeplay name mangling
The Codeplay VectorC C++ compiler uses the same name mangling scheme as Microsoft
with some exceptions. I have not checked it systematically, but I have found the following
differences:•long double is supported in both 64 bits and 80 bits precision. Both are coded as O.

•

The method for abbreviating types (page 32) does not apply to two-character codes.
It does apply to pointers and references to such types.

•

The coding of data member pointers and member function pointers do not include
the class name.

•Arrays as function parameters are coded as pointers (P).

•Global one-dimensional arrays are coded with the array size. The encoding of thesize is slightly different from the Microsoft scheme.

8.10 Other compilers
The PathScale compiler uses Gnu name mangling. The PGI compiler also uses Gnu namemangling, even under Windows.

8.11 Turning off name mangling with extern "C"

43

Table 21. Function name prefixes with extern "C" declaration
Gnu3
Linux, BSD 64
Gnu3Linux, BSD 64

_
_
_
@

Gnu2, Gnu3Linux, BSD 32

@
UC
_

_
_
_
_

Gnu2, Gnu3Linux, BSD 32

_
_

Gnu3
Windows 32

_
_

Gnu2
Windows 32

_
_
_
_

Watcom 16, 32

_
_
_
@

Borland 16, 32

Microsoft
32 bit_____cdecl__stdcall__fastcall
pascal__fortran

Digital Mars

Microsoft
16 bit(default)

Microsoft64 bitCall typeUC
UC

Explanation:_
name has underscore prefix@name has @ prefixUC
entire name converted to upper case
Table 22. Function name postfixes with extern "C" declaration
Gnu2
Windows 32

Gnu3
Windows 32__cdecl__stdcall__fastcall
pascal__fortran

Watcom 16, 32(default)

Borland 16, 32

Digital Mars

Microsoft64 bitMicrosoft
32 bitMicrosoft
16 bitCall type

@S

@S
@S

_
@S
@S

@S

@S
_

Explanation:_
underscore appended after name
@S
name followed by @, followed by the combined size of all parameters expressed as
the number of bytes pushed on the stack as a decimal number. For __fastcall,register parameters are included by the size they would have if they were transferredon the stack.
The extern "C" attribute on a C++ function turns off name mangling so that the public or
external name becomes compatible with the C language. This can be useful for solving
problems with incompatible name mangling schemes. In 16 and 32 bit DOS and Windows
systems, however, there is still some name decoration. The public and external names get
the prefixes shown in table 21 and the postfixes shown in table 22. This may cause
compatibility problems for __stdcall and __fastcall functions.
The extern "C" attribute is only allowed for functions that can be coded in C. Hence,
overloaded functions and member functions cannot have the extern "C" attribute. When
compatibility with all compilers is desired, you may give all functions the extern "C"
attribute, replace overloaded functions by functions with different names, and replace
member functions by friend functions.
External functions with the __declspec(dllimport) attribute have prefix __imp_ in allcompilers except Borland.
44

Functions with the names main and WinMain always have extern "C" coding. In addition,some compilers give WinMain the __stdcall attribute by default.

8.12 Conclusion
Various characteristics of the different name mangling schemes are compared in table 23.
Table 23. Comparison of name mangling schemes
Microsoft
unambigous and reversible
includes type of global objects
includes storage classincludes function return typeincludes calling convention
includes function modifiers
compact
allows case insensitive linking
human readable
non-C characters used

yes
yes
yes
yes
yes
yes
yes
yes
no
$ @ ?

Borland
yes
no
no
no
yes
few
somewhat
no
yes
$ @ %

Watcom
yes
yes
yes
yes
no
some
yes
no
yes
$?()[]:.

Gnu2
no
no
no
no
(no)
no
somewhatnoyes$ or .

Gnu3+
no
no
no
no
(no)
no
yes
no
yes
none

The Gnu2 and Gnu3 schemes use only characters that are valid in C names in most or allcases. The reason for this is that these schemes have their origin in tools that convert from
C++ to C, so the mangled names must be valid C names. This has the disadvantage thatthe mangled name cannot unambiguously be translated back to the original C++
declaration. The mangled name of a C++ function could in principle be the unmangled nameof a variable. This disadvantage is avoided if the mangled code contains characters that are
not valid in C++ names. On the other hand, the character set should be restricted tocharacters that can be generated by common assemblers in order to allow compilation
through assembly or linking with assembly language modules. The characters $ ? @ areallowed in Microsoft and Borland assemblers. The Gnu assembler allows . and $. The
Watcom assembler allows all characters in public symbols.
We will prefer that a name mangling scheme is complete, consistent and compact. It should
also be relatively easy for humans to interpret the code, though this requirement conflicts
with the desire for compactness. The Microsoft and Gnu3 schemes are the ones that havethe most consistent syntax. It is recommended that new compilers use one of these two
schemes for the sake of compatibility.

9 Exception handling and stack unwinding
An exception, a thread termination, or a longjmp can lead to a process where functions areexited without the normal return being executed. Objects that go out of scope by thisprocess may have destructors that need to be called. In order to find all objects that need tohave their destructors called, the system must unwind the stack to trace backwards throughconsecutive function calls. Some systems also use stack unwinding for recovering registers
saved on the stack after an exception.
If a function has any local objects with destructors and if an exception or longjmp or threadtermination can occur inside the function or any of its child functions, then this function must
support stack unwinding. Some ABI's require that all functions have stack unwinding
information if the function saves anything on the stack or calls any other function. The
method of stack unwinding is different for different systems. This process often uses stack
frames based on BP/EBP/RBP. The function prolog must save the old value of the frame
pointer and save the value of the stack pointer in the frame pointer register:_FunctionWithFramePointer PROC NEAR

45

PUSH
EBP
MOV
EBP, ESP...
MOV
ESP, EBP
POP
EBP
RET
_FunctionWithFramePointer ENDP

Additional information about destructors to be called may be provided either by the function
itself or by data in a static data segment designed for only this purpose.
If a structured exception or longjmp or thread termination can happen inside a function or
any of its child functions, then it is not allowed to use BP/EBP/RBP for any other purpose
than a frame pointer in systems that rely on BP being a frame pointer.
Detailed information about specification of the unwind mechanism for x64 systems can befound in the respective ABI's. See literature, page 59. I don't have the detailed informationfor 32-bit systems.

10 Initialization and termination functions
A C++ module may contain global objects with constructors that must be called before mainis called, and destructors to be called after main has returned. There may be otherinitialization and termination tasks to perform, too. For this purpose, the compiler provides alist of pointers to initialization functions and termination functions. These lists of function
pointers are stored in separate data segments designed for only this purpose. These lists
may contain additional information about the priority or order in which the initialization andtermination functions should be called. The names of these segments and the format ofthese tables are different for different compilers.

11 Virtual tables and runtime type identification
A class with virtual member functions always has a virtual table. This is a table of member
function pointers used for finding the right version of a polymorphous function. Eachinstance of the class has a pointer to the virtual table. Microsoft, Borland and Gnu version
3.x compilers place the pointer to the virtual table at the beginning of the object, while
Watcom and Gnu version 2.x compilers place it at the end of the object. This affects theoffset of all data members of the class so that member functions may be incompatible
between compilers.
Information for runtime type identification is usually stored in connection with the virtualtable.
The "Itanium C++ ABI" includes more detailed information about the representation of virtualtables and runtime type identification. This information may apply to other platforms as well.

12 Communal data
Communal data are data that may occur identically in more than one module, but the final
executable should contain no more than one instance of this redundant information. The
linker may check that all instances are identical and store only one instance in theexecutable file. Communal data are used for virtual tables, template instantiations, andpossibly for global data.
46

A different use of communal data is for data that may or may not be needed in the final
executable. This is typically the case with the non-inlined versions of inlined functions. The
compiler does not need this function in the module it is currently compiling, but it may or
may not be called from a different module. The compiler can then allow the linker to remove
the communal function if it is not needed.
You cannot expect communal data produced by different compilers to be identical or to be
identified in the same way in the object files. Assemblers may not support communal data.

13 Memory models
A memory model defines the address ranges and addressing modes for code and data.
Different memory models are used for 16-, 32- and 64-bit systems.

13.1 16-bit memory models
The historic 16-bit DOS operating system had no protection against accessing false
addresses and no distinction between physical and logical (virtual) memory addresses. A
protected operating system can emulate the 8086 memory space using the virtual 8086
mode of a 32-bit processor. The memory space is divided into segments no bigger than 64
kbytes. The real address of an object is equal to the segment multiplied by 16 plus the 16bit unsigned offset. A maximum segment of 0xFFFF and a maximum offset of 0xFFFF gives
a maximum total address of 0xFFFF * 0x10 + 0xFFFF = 0x10FFEF. The following memory
models are used:

Tiny
Code and data are contained in the same segment no bigger than 64 kbytes. The code
starts at address 0x100 relative to the segment start. The executable file does not have theusual extension .exe but instead .com.

Small
There are two segments of max. 64 kbytes each, one for code and one for data and stack.

MediumThe code can exceed 64 kbytes. Far function calls are needed. Data and stack are limited
to one segment of max. 64 kbytes.

Compact
The code is limited to 64 kbytes. The stack is limited to 64 kbytes. Data can exceed 64
kbytes. Far pointers are used for data.

Large
The code can exceed 64 kbytes. Data can exceed 64 kbytes. The stack is limited to 64
kbytes. Far pointers are used for code and data.

Huge
Same as large. A single data structure can exceed 64 kbytes by modifying not only theoffset but also the segment of a pointer when it is incremented.

Protected
Windows 3.x uses protected segmented memory with 16-bit offsets. It is similar to the above
models, but segment registers contain segment selectors rather than physical addresses.
Data structures bigger than 64 kbytes can be accessed by adding 8 to the segment
descriptor for each 64 kbytes increment or by using a 32-bit offset in case a 32-bit processor
is used.
47

13.2 32-bit memory models
32-bit Windows, Linux, BSD and Intel-based Mac all use the flat memory model. Application
code uses only one segment with a maximum size of 2 Gbytes. All pointers use 32-bit
signed addresses. Negative addresses are reserved for the operating system kernel anddevice drivers.

13.3 64-bit memory models in Windows
The combined size of code and static data is limited to 2 Gbytes so that 32-bit self-relative(rip-relative) addresses can be used. The image base (see chapter 14) is mostly below 231,
but not always. 32-bit absolute addresses are rarely used. Dynamically allocated data andstack can exceed 2 Gbytes. Pointers are usually 64 bits. 32-bit pointers relative to the image
base are sometimes used for arrays and pointer tables. Negative addresses are reserved
for the system kernel.

13.4 64-bit memory models in Linux and BSD
Linux x64 small memory modelThis is the default memory model in x64 Linux and BSD. Code and static data are limited to
2 Gbytes and are always stored at addresses below 231. This allows the compiler to use 32bit signed absolute addresses, typically for addressing static arrays. However, later versionsof the Gnu compiler (version 6 and probably version 5 as well) never use 32-bit absoluteaddresses, and the linker version 2.28 does not allow 32-bit absolute addresses eventhough the small memory model is used (seehttps://stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longerallowed-in-x86-64-linux).
Dynamically allocated data and stack can exceed 2 Gbytes. Pointers are usually 64 bits.

Linux x64 medium memory model
Static data objects bigger than the "large-data-threshold", typically 64 kbytes, are stored in alarge data section which can exceed 2 Gbytes. Code and smaller static data are still limited
to addresses below 231. The compiler option is -mcmodel=medium.

Linux x64 large memory model
Code and data can exceed 2 Gbytes. Functions and static data are accessed with 64 bit
absolute addresses, which is quite inefficient. The compiler option is -mcmodel=large.

Linux x64 position-independent modelThis model is used for shared objects (dynamic libraries). The size of each executable orshared object is limited to 2 Gbytes. Functions and data inside the executable are accessedwith 32-bit relative addresses. External functions and data are accessed through 64-bit
pointers. The compiler option is -fpic or -fpie (the latter option avoids the use of GOT
and PLT tables for accessing local data and functions).

Linux x64 kernel
The system kernel and device drivers use negative addresses between -231 and 0.

13.5 64-bit memory models in Intel-based Mac (Darwin)
The default memory model limits the combined size of code and static data in each
executable file to 2 Gbytes so that 32-bit self-relative (rip-relative) addresses can be used.
By default, all code is loaded at addresses above 232. The address space below 232(pagezero) is blocked so that any attempt to use 32-bit absolute addresses will generate anerror. Dynamically allocated data and stack can exceed 2 Gbytes. Pointers are usually 64
bits. Pointer tables can use 32-bit signed addresses relative to an arbitrary reference point.
48

Certain system functions can be accessed at fixed 64-bit addresses in the so-called
commpage.
It is possible to place code at addresses below 231 and reduce the size of pagezero so that32-bit absolute addresses can be used, but this is rarely done.

13.6 64-bit memory models in Cygwin
Cygwin is a system that emulates the behavior of Linux tools under Windows. Cygwin64 isusing a medium memory model by default. This means that static data are accessed by 64bit absolute addresses. The purpose of this memory model is to make it possible to address
a data object in another executable file, as described on page 51 below. The performance isreduced considerably by the medium memory model. This performance cost can be avoided
by compiling with the option -mcmodel=small with a gcc or Clang compiler, except in therare case where you are linking directly to a data object in another executable file.
It is recommended to use Mingw64(msys2) instead of Cygwin when performance is critical.
Mingw64 is using a standard Windows memory model.

14 Relocation of executable code
Most operating systems use the same, or almost the same, file type for executable files andobject files. An executable file may need relocation when it is loaded into memory,depending on the load address. The load address or image base is the virtual memory
address at which the beginning of the executable file is placed. Relocation is a process
where all cross-references using absolute memory addresses in the file are modified
according to the load address.
The executable file may be relocated by the linker to a preferred load address. If thepreferred load address is not vacant then the executable file has to be relocated again by
the loader to another load address.
The most common values for the preferred load address are: 0x400000 for 32-bit and 64-bit
Windows and 64-bit Linux systems; 0x8048000 for 32-bit Linux; 0x1000 for 32-bit Mach-O
systems; 0x100000000 for 64-bit Mach-O systems. Other positive values can be used aswell. The linker can adjust all cross references in the exe file according to the preferred load
address. If a process has only one executable file, then the operating system can map thephysical memory address at which this file is loaded to the desired virtual address, e.g.
0x400000. A load address less than 231 = 0x80000000 makes it possible to use a small
memory model where 32-bit signed absolute addresses can be used in 64-bit systems.
Negative addresses are reserved for the operating system kernel.
A dynamically linked library or shared object will need relocation at load time if the preferredload address is occupied by another library. A dynamic library will usually need at least two
memory pages: a shared memory page for the code section and possibly read-only data,
and a non-shared memory page for the writable data section. The size of a memory page iseither 4 kbytes or 2 Mbytes.

Relocation in Windows
The preferred load address for the main executable is traditionally 0x400000, but otheraddresses are possible. The preferred load address for a DLL differs. A DLL may be loadedat an address higher than 231 in 64-bit mode. There is no compiler option to distinguishbetween main executables and DLLs. Therefore, 32-bit absolute addresses are rarely usedin 64-bit Windows. Instead, code and data within the same executable or DLL are accessedwith 32-bit addresses relative to the instruction pointer (rip-relative) or relative to the load
address (image-relative).
49

Multiple processes can use the same virtual memory addresses mapped to different
physical addresses. When a DLL is shared between multiple processes, the sections
typically have the same virtual addresses in all processes when the DLL is loaded at thepreferred address. If relocation is needed in the code section then there will be multiple
instances of the code section, while only explicitly shared data sections will be shared.

Relocation in LinuxThe preferred load address for the main executable is often 0x8048000 in 32-bit mode and0x400000 in 64-bit mode.
Shared objects may be loaded at negative addresses in 32-bit mode, but not in 64-bit mode
where addresses above 231 are used for shared objects.
When a shared object is shared between multiple processes, the same sections havedifferent virtual addresses in the different processes. The distance between the code
section and the data section is the same for all processes so that relative addresses can beused. The code section of a shared object is shared between processes unless it ismodified by relocation. A shared object is usually compiled as position-independent code
(option -fpic) to avoid relocations in the code section.
32-bit absolute addresses are used in the main executable, but not in shared objects in 64bit mode. A 64-bit shared object must therefore be compiled as position-independent code
(option -fpic or -fpie) to avoid 32-bit absolute addresses.
Shared objects usually have global offset tables (GOT) with pointers to static and global
data, and procedure linkage tables (PLT) with pointers to global functions. All global
symbols are accessed through these pointer tables when the compiler option -fpic is used.
In 32-bit mode, the GOT is also used for local variables. The purpose of these tables is to
mimic the behavior of static libraries. If a function in the main executable has the same
name as a function in the shared object then the version in the main executable will be
used, even when called from the shared object. The same applies to global variables. Thisfeature that allows local access inside the shared object to be redirected comes at a highprice because all accesses must go through the GOT and PLT tables. See the chapter"Static versus dynamic libraries" in manual 1: "Optimizing software in C++" for tips about
how to avoid these pointer tables.

Relocation in BSD
This is similar to Linux.

Relocations in Mac OS X
Position-independent code is used by default even for the main executable, though this is
not necessary. It is possible to speed up the main executable in 32-bit mode by making thecode position-dependent (option -fno-pic).
In 64-bit mode, most addresses use a 32-bit signed offset relative to the instruction pointeror to an arbitrary reference point.
Shared objects rarely use global offset tables (GOT). Procedure linkage tables are not used
for internal references.
When a shared object is shared between multiple processes, the same sections have thesame virtual addresses in the different processes.

Relocations in 16-bit systems
16-bit DOS and Windows 3.x systems use segmented memory models where all memory
addresses are of the segment:offset kind. Executable files must be relocated when loaded50because the operating system cannot map the image to an arbitrary address. Only thesegment part of a segment:offset address needs to be relocated. In DOS, the segment
address is modified in the executable code. In Windows 3.x the segment descriptor table ismodified.
The 16-bit systems do not use the same file format for executable files as for object files.

Relocations in Cygwin
Cygwin tools run under Windows and use the same relocation process as Windows. An
undocumented extra step called pseudo-relocation is added when an executable file (.exeor .dll) is loaded. The pseudo-relocation makes it possible to get direct access from one
executable file to a data object in another executable file. The purpose of this is to emulate
the behavior of Linux shared objects. This feature comes at a high price, when we consider
that direct access to a data object in another executable must be considered bad programming practice by modern standards.

14.1 Import tables
Almost all executable files contain function calls to functions in other DLLs or sharedobjects. In most cases, these function calls go via an import table in the executable file. The
loader fills the import table with the addresses of the external functions when the program
and the DLLs or shared objects are loaded. The implementation of the import table differs
among systems.
Some systems allow lazy binding of external references. Lazy binding means that theaddress of the external function is not inserted in the import table until the first time thefunction is called. The advantage of lazy binding is that the address of an external functionneeds not be calculated in case the function is never called. The disadvantage is aconsiderable delay the first time each external function is called.
It is often possible to use static linking instead of dynamic linking for calls to libraryfunctions. The idea of static linking is that the required library functions, but not the entire
function library, are copied into the executable file by the linker. The references to thesefunctions can then be resolved at link time rather than at load time.

15 Object file formats
There are at least four different object file formats in common use for x86 platforms. These
are OMF, COFF also called PE, ELF and Mach-O format. The old a.out format is rarely
used any more.

15.1 OMF format
OMF stands for Object Module Format. This format is also called Microsoft 8086
relocatable. The OMF format is used for 16-bit operating systems (DOS, Windows 3.x andearlier). Some compilers (Borland, Watcom, Symantec, Digital Mars) also use OMF format
for 32-bit Windows.
This format was originally designed for the segmented memory model of the 16-bit 8088
microprocessor, used in the first IBM PCs. The OMF format allows the resolution ofaddresses relative to an arbitrary reference frame representing a segment or group ofsegments. A reference frame starts at an address divisible by 16 and can span 64 kbytes.
Reference frames are allowed to overlap. Overlays are supported (i.e. allowing multiple
pieces of code to share the same memory space).
51

The OMF object file consists of a chain of records where the first byte of each record
indicates the type of data contained in the record. No record can contain more than 1 kbyteof data.
The OMF format was designed for compactness at the time of the first IBM PCs where theonly means of storage was one or two 360 kbytes floppy disk drives. The OMF format
allows several different methods for compressing bytes that are zero or repeated, not only inthe binary code and data, but also in relocation tables. Repeat-blocks can be nested to an
unlimited depth. These compression features make the interpretation of OMF files
complicated and error-prone. The method for compressing repeated relocation informationis hardly used any more, if it ever was. Repeat-blocks in data segments are still used bysome tools. The Microsoft assembler can generate relocations in repeated data although
this is discouraged and not supported by all linkers.
The OMF standard also specifies a format for static libraries. The OMF library uses a hashtable for listing the public symbols of all modules in the library. Other formats use a simple
sorted list or even an unsorted list for the same purpose. The use of a hash table requiresthat all linkers and library managers use exactly the same hashing algorithm. Unfortunately,
the official definition of the hashing algorithm is not as clear and stringent as one could wish
for. The gain in efficiency from using a hash table rather than a sorted list is minimal, andnot enough to justify the considerable increase in complexity, in my opinion.
An OMF library can have an optional "extended dictionary" in addition to the hash table. The
extended dictionary specifies dependencies between modules in order to facilitate one-passlinking. There are two different and incompatible formats for the extended dictionary. The
original IBM/Microsoft format and a proprietary format used by Borland. Extended
dictionaries are rarely used.

Limitations:
Segment word size: 16 or 32 bits. Can be mixed.
Segment alignment: Supports only 1, 2, 4, 16, and either 256 or 4096.
Max identifier length: 255 characters.
Max external symbols: 64 k.
Max number of segments: 64 k.
Max segment size: 4 Gbytes.
Max number of modules in library: < 64 k.
Some old linkers limit the size of the library hash table to 251 blocks of 37 buckets each.
This limits the number of public symbols in a library to between 251 and 9287, dependingon the lengths of the names. Even for linkers that allow more than 251 blocks there aresomewhat unpredictable limitations in the hash table.

15.2 COFF format
COFF stands for Common Object File Format. This format was first used in UNIX system V,
but later superseded by ELF. A modification of the COFF format is used in Windows. The
Windows version of COFF is also called PE (Portable Executable). The 64-bit version iscalled PE32+. The same format is used for object files and executable files. The COFF
format used under windows is a Microsoft adaptation of the COFF format used on certain
other platforms.
The COFF format is used for object files in 32-bit and 64-bit Windows by Microsoft, Intel,
Gnu, and Clang compilers. The Codeplay compiler for 32-bit Windows can use the OMF,
COFF or ELF32 formats.
The COFF format uses many different data structures, which makes it somewhat
complicated. The definition of the data structures is not in agreement with the defaultalignment rules of modern compilers.
52

Different object file formats differ in the way self-relative references are implemented, due tothe way the CPU calculates relative addresses. The CPU calculates self-relative addresses
relative to the value of the instruction pointer after the instruction, not relative to the positionof the address field in the instruction code. The distance from the position of the address
field (relocation source) to the reference point used by the CPU is 2 in 16-bit code, 4 in 32bit code, and 4, 5, 6 or 8 in 64-bit code. The COFF and OMF formats have different
relocation codes for each of these distances so that the necessary correction can beinserted by the linker. The ELF and Mach-O formats have no inherent recognition of thisdifference, so that the correction must be inserted as an explicit addend in the object file.
The COFF format allows the specification of image-relative references, which are notavailable on other platforms. Image-relative references are used in 32-bit mode for debug
information. 32-bit image-relative references are used in 64-bit mode for exception handlinginformation and in general for saving space where 64-bit pointers would otherwise beneeded.

Limitations:
Segment word size: 32 or 64 bits.
Max number of sections: 32 k.
Max file size: 4 Gbytes.
Max section size: 4 Gbytes.
Max relocations per section: 64 k.
Max library size: 4 Gbytes.

15.3 ELF format
ELF stands for Executable and Linkable Format. This format has replaced older formats likea.out and COFF in Linux and BSD. Gnu tools running under Linux and BSD often accept
several other formats, not including the formats used under Windows. Gnu tools runningunder Windows accept COFF and ELF formats.
The ELF format is designed to be flexible and expandable. The sizes of all data structuresare specified explicitly so that they can be expanded without losing backwards compatibility.
This makes the ELF format far more clear and robust than other formats.

Limitations:
Segment word size: 32 or 64 bits.
Max number of sections: 64 k.
Max file size: 4 Gbytes for 32 bits, 264 bytes for 64 bits.
Max section size: 4 Gbytes for 32 bits, 264 bytes for 64 bits.
Max string table size: 4 Gbytes.
Max number of symbols: 16 M for 32 bits, 4 G for 64 bits.
Max library size: 4 Gbytes.

15.4 Mach-O format
Mach-O stands for Mach Object. This format is used in Mac OS systems for object files andexecutable files. The following description applies only to the Intel-based Mac OS X
(Darwin) system.
Mach-O object files have only one segment record comprising several section records.
Mach-O executable files have several segment records.
The Mach-O format allows the specification of addresses relative to an arbitrary reference
point in an arbitrary section. This addressing method, which is not available in the otherobject file formats, is used for position-independent code.
53Position-independent code and lazy binding is used by default by the Gnu compiler for 32bit Mac OS X. This makes code execution less efficient. Position-independent code isrequired only for shared objects (dynamic link libraries) in Mac OS X.
Local symbols are referenced by their addresses rather than by their names in 32-bit MachO files, where the COFF and ELF formats have symbol table entries for local symbols.

Limitations:
Section name length: 16 characters.
Max file size: 4 GB.
Max section size: 16 MB for position-independent code, 4 GB for 32 bits, 264 bytes for 64
bits.
Max number of sections: 16 M.
Max number of symbols: 16 M.
Max library size: 4 GB.

15.5 a.out format
a.out stands for Assembler Output. This format is used in older versions of UNIX and similarsystems. The name a.out remains as the default name for linker output files, even thoughthese files are not in a.out format any more. Some linkers still support the a.out format.

15.6 Comparison of object file formats
The ELF format stands out as the most consistent, clear, robust and flexible of the object fileformats. The other formats are full of patches and appear kludgy in comparison. I would
recommend the ELF format for new applications. The OMF format should be used only for
16-bit applications.

15.7 Conversion between object file formats
It may be possible to convert object files from one format to another in simple cases. A tool
for this purpose named objconv is available at www.agner.org/optimize. This tool can also
be used as a cross-platform library manager. See the objconv manual for details andmentioning of other relevant tools.
Conversion of an object file will fail if the file contains references of a type that is notsupported by the target format, e.g. image-relative references in COFF files or positionindependent code in Mach-O files.
An object file that has been converted from one platform to another will work on the target
platform only if all calling conventions etc. are the same on both platforms and there is noreference to platform-specific library functions or system functions.
Differences in name-mangling conventions can be fixed by using extern "C" declarations or
by using objconv to change symbol names in the object file.
The use of converted object files can fail to work for many reasons. All the compatibility
problems described in the present document should be considered in order to predictwhether object file conversion is likely to work. While the calling conventions are almost thesame in all 32-bit x86 systems, they are quite different in 64-bit systems. A call stub isneeded for converted functions in 64-bit systems.
Conversion of compiler-generated object files should be used only as a last resort when thesource code is not available. Conversion of object files made from assembly code can be54

expected to work if the assembly source is carefully inspected for possible compatibility
problems.

15.8 Intermediate file formats
Some compilers have features for optimizing code across function calls and modules (whole
program optimization). These compilers use intermediate files containing partially compiled
code. The format for these intermediate files is not standardized. It is not even guaranteed
to be compatible between different versions of the same compiler. The intermediate fileformat is therefore not suitable for distributing function libraries.
It would be useful to have a standardized object file format that includes information about
which registers each function modifies, in order to optimize register allocation. Such a fileformat has not been implemented for any of the platforms I have studied.
Java compilers generate an intermediate code called Java bytecode. This code is either
interpreted or just-in-time compiled by a Java machine on the target platform. The byte codeis platform independent and needs no translation. Java bytecode is less efficient thancompiled machine code.
A similar technology is used by C++, C# and Visual Basic compilers for the Microsoft .NET
platform. The bytecode is just-in-time compiled by the .NET runtime framework on the target
machine. The bytecode is expected to work on any platform for which a .NET framework
exists. .NET bytecode is less efficient than compiled machine code.

16 Debug information
Compilers differ in the way they store debugging information and information for profilers inobject files and executable files. Thus, it may not be possible to use the same debugger fordifferent compilers, even on the same platform. The information stored includes names ofsource files, line numbers, and variable names. I have not studied the details of how debug
information is stored.

17 Data endian-ness
All systems based on 16, 32 and 64 bit x86 microprocessors use little-endian data storage,i.e. the least significant byte of a multi-byte data unit is stored at the lowest address. Manyother microprocessor platforms use big-endian data storage. This can give rise tocompatibility problems when exchanging binary data files between platforms, and when
porting C++ programs that explicitly address part of a data object, such as the sign bit of afloating point number.

18 Predefined macros
Most C++ compilers have a predefined macro containing the version number of thecompiler. Programmers can use preprocessing directives to check for the existence of thesemacros in order to detect which compiler the program is compiled on and thereby fix
problems with incompatible compilers.

55

Table 24. Compiler version predefined macros
Compiler
BorlandClang
Codeplay VectorC
Digital Mars
GnuIntel legacy “Classic”
Intel LLVM based
Microsoft
Pathscale
Symantec
WatcomPredefined macro__BORLANDC____clang____VECTORC____DMC____GNUC____INTEL_COMPILER__INTEL_LLVM_COMPILER_MSC_VER__PATHSCALE____SYMANTECC____WATCOMC__

Unfortunately, not all compilers have well-documented macros telling which hardware
platform and operating system they are compiling for. The following macros may or may not
be defined:
Table 25. Hardware platform predefined macros
Hardware platformx86
x86-64IA64
DEC Alpha
Motorola Power PC
Any little endian
Any big endian

Predefined macro_M_IX86, __INTEL__, __i386___M_X64, __x86_64__, __amd64__IA64____ALPHA____POWERPC____LITTLE_ENDIAN____BIG_ENDIAN__

Table 26. Operating system predefined macros
Operating system
DOS 16 bit
Windows 16 bit
Windows 32 bit
Windows 64 bit
Cygwin
Mingw
Linux 32 bit
Linux 64 bit
BSD
Mac OS
OS/2

Predefined macro__MSDOS__, _MSDOS_WIN16_WIN32, __WINDOWS___WIN64, _WIN32__CYGWIN____MINGW32__, __MINGW64____unix__, __linux____unix__, __linux__, __LP64__, __amd64__unix__, __BSD__, __FREEBSD____APPLE__, (__DARWIN__, __MACH__)__OS2__A more comprehensive list of predefined macros can be found at predef.sf.net.

56

19 Available C++ Compilers
19.1 Microsoft
Microsoft Visual C++ comes in several different versions. The professional edition, which isrelatively expensive, includes integrated development environment (IDE) and many tools
including debugger and profiler. A limited edition is available for free. The Visual Studio IDE
can use other compilers as plugins, including Clang and Intel.

19.2 Borland/Embarcadero
Borland C++ compilers and development tools were once very popular. After several years
where the compiler was not properly maintained, they have switched to using the Clangcompiler front end.

19.3 Watcom
Watcom C++ is no longer sold commercially, but it has been continued as an open source
project. The Watcom compiler is available from www.openwatcom.org, including integrated
development environment, debugger, profiler, assembler, disassembler, and other tools.
The compiler is currently not up to date.
Users of this compiler should be aware that register usage and calling conventions differ
from other compilers. You must fix these problems by using #pragma's when defining or
calling DLL functions and when combining with tools from other vendors.

19.4 Gnu
Gnu C++ is an open source compiler that comes with most distributions of Linux, BSD and
Mac OS. Various Windows versions are available. The version from www.msys2.org is
recommended. Also available is an assembler (GAS) which uses the AT&T syntax bydefault.

19.5 Clang
Clang is a front end for the Low Level Virtual Machine (LLVM) open source compiler
available for all x86 platforms. It is the default compiler for newer versions of x86-based Mac
OS. A Windows version is available as a plugin to Microsoft Visual Studio.

19.6 Digital Mars
Digital Mars C++ compiler is a continuation of Zortech C++ and Symantec C++, available
from www.digitalmars.com. The compiler package is cheap, and a command line version isavailable for free. Both Symantec C++ and Digital Mars C++ are binary compatible with
Microsoft C++ in most respects, including calling conventions and name mangling. The
compiler is not up to date. The latest version is from 2013, supporting only 32-bit Windows.

19.7 Codeplay
The Codeplay VectorC C++ compiler is no longer available.

19.8 Intel C++ compiler Classic
Intel compilers are available for Windows, Linux, and Intel-based Mac OS X. This legacy
compiler is now named “Classic”. It used to be a relatively expensive compiler, but is now
available for free together with the newer Intel LLVM-based compiler. The Windows version
is binary compatible with Microsoft compilers. The Linux version is binary compatible with
Gnu compilers. Code produced with the Intel Classic compiler has reduced performance
when running on a non-Intel processor. The Intel Classic compiler is not recommended for
new projects.

5719.9 Intel oneAPI C++ compiler, LLVM based
This is a forking of the Clang compiler with added Intel features and Intel function libraries. It
performs better than the Intel Classic compiler. It is possible to generate code that works
well on non-Intel microprocessors.

58

20 Literature
20.1 ABI's for Unix, Linux, BSD and Mac OS X (Intel-based).
Despite its name, the "Itanium C++ ABI" applies to other hardware platforms than the
Itanium, except for a few processor-specific details, though not all x86 compilers conform tothis ABI. The "Itanium C++ ABI" contains valuable information about the representation ofmember pointers, virtual tables, runtime type identification and name mangling, not foundanywhere else. Most of this information applies to 32-bit and 64-bit Gnu compilers for x86
platforms. See also https://refspecs.linuxfoundation.org/.
•

System V Application Binary Interface. AMD64 Architecture Processor Supplement
http://x86-64.org/documentation/abi.pdf
https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI•

Itanium C++ ABI. Revision 1.86. Draft, 2005. www.codesourcery.com/cxx-abi/•

Itanium C++ ABI: Exception Handling. Revision: 1.22. Draft, 2005.
www.codesourcery.com/cxx-abi/abi-eh.html

Linux, BSD, Mac OS 32 bits:•

SYSTEM V. APPLICATION BINARY INTERFACE. Intel386 Architecture Processor
Supplement. Fourth Edition.

Mac OS X IA32•

Mac OS X ABI Function Call Guide. 2006-04-04.
developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/This appears to be the most up-to-date specification of the IA32 ABI. Many of thespecifications, but not all, apply to Linux and BSD platforms as well.

Linux and BSD, 64 bits:•

System V Application Binary Interface. AMD64 Architecture Processor Supplement.
Draft Version 0.99.8, 2016. https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI

20.2 ABIs for Windows
Windows, 32 bits:•

C++ Language Reference: Calling Conventions. msdn.microsoft.com, 2006.

Windows, 64 bits:•

x64 Software Conventions. msdn.microsoft.com, 2006.

Amendment for YMM registers:••

Intel® Advanced Vector Extensions Programming Reference.
http://software.intel.com/en-us/avx/
Upcoming Intel®64 Instruction Set Architecture Extensions -Intel®Advanced Vector
Extensions (Intel®AVX). Intel Developer Forum 2008.

5920.3 Object file format specifications
OMF:•

Tool Interface Standards (TIS): Relocatable Object Module Format (OMF)
Specification. Version 1.1. TIS Committee, 1995.

•

United States Patent 5408665, 1995. Describes the Borland library extended
dictionary format.

COFF:
•

Visual Studio, Microsoft Portable Executable and Common Object File Format
Specification. Revision 8.0, 2006. download.microsoft.com.

ELF:•

Executable and Linkable Format (ELF). Version1.1. Tool Interface Standards (TIS).

Mach-O:•Mac OS X ABI Mach-O File Format Reference, 2007. Apple Computer, Inc.
developer.apple.com.

21 Copyright noticeThis series of five manuals is copyrighted by Agner Fog. Public distribution and mirroring is
not allowed. Non-public distribution to a limited audience for educational purposes isallowed. The code examples in these manuals can be used without restrictions. A creative
commons license CC-BY-SA shall automatically come into force when I die. See
https://creativecommons.org/licenses/by-sa/4.0/legalcode

22 Acknowledgments
Thank you to the many people who have sent me additional information and corrections formy manuals and provided other kinds of help. This allows me to keep improving thesemanuals.

60