The C ABIs of the other pages say how a function receives its arguments, but not what a C++ program adds: the hidden this, the names of overloaded functions, virtual tables, pointers to members, run-time type information and exceptions. Those rules make up a C++ ABI, and on x86 there are two:

The two C++ ABIs of x86.
C++ ABIUsed by
Itanium C++ ABIGCC; Clang on Linux, the BSDs, macOS and for MinGW-w64
Microsoft C++ ABIMSVC, and Clang for Windows targets with the MSVC ABI, including clang-cl

The Itanium C++ ABI was written for Intel’s Itanium, but most of it is independent of the processor. GCC’s C++ has been based on it since GCC 3.2, and other compilers implement it too, notably on GNU/Linux and the BSDs. The Microsoft C++ ABI has no specification of that kind: Microsoft documents parts of it, such as decorated names and the forms of member pointers, and Clang implements it for its Windows targets. Both sit on the C convention of their platform, so MinGW-w64 code uses the Microsoft x64 registers with the Itanium C++ ABI. All listings on this page come from Clang, which compiles for both.

this

A non-static member function takes the object’s address as a hidden argument. The Itanium C++ ABI passes it as the first argument, so on x86-64 it arrives in RDI and on i386 in the first stack slot. Microsoft x64 passes it first too, in RCX. On 32-bit Windows, member functions use their own convention, __thiscall: this in ECX and the other arguments on the stack, which the callee removes.

Counter::add in each ABI: this in RDI, RCX, at 4(%esp) and in ECX; the 32-bit Windows version pops its argument with retl $4.

cxx-this.cpp

// A member function: this is an argument that the source does not
// write.
struct Counter {
	int n;
	int add(int k);
};

int Counter::add(int k)
{
	return n += k;
}

Clang 23.1.2 x86_64-linux-gnu

AT&T syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -S cxx-this.cpp

_ZN7Counter3addEi:
        movl    %esi, %eax
        addl    (%rdi), %eax
        movl    %eax, (%rdi)
        retq

Intel syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-this.cpp

_ZN7Counter3addEi:
        mov     eax, esi
        add     eax, dword ptr [rdi]
        mov     dword ptr [rdi], eax
        ret

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -S cxx-this.cpp

"?add@Counter@@QEAAHH@Z":
        movl    %edx, %eax
        addl    (%rcx), %eax
        movl    %eax, (%rcx)
        retq

Intel syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-this.cpp

"?add@Counter@@QEAAHH@Z":
        mov     eax, edx
        add     eax, dword ptr [rcx]
        mov     dword ptr [rcx], eax
        ret

Clang 23.1.2 i686-linux-gnu

AT&T syntax clang --target=i686-linux-gnu -march=i686 -O2 -fno-asynchronous-unwind-tables -S cxx-this.cpp

_ZN7Counter3addEi:
        movl    4(%esp), %ecx
        movl    (%ecx), %eax
        addl    8(%esp), %eax
        movl    %eax, (%ecx)
        retl

Intel syntax clang --target=i686-linux-gnu -march=i686 -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-this.cpp

_ZN7Counter3addEi:
        mov     ecx, dword ptr [esp + 4]
        mov     eax, dword ptr [ecx]
        add     eax, dword ptr [esp + 8]
        mov     dword ptr [ecx], eax
        ret

Clang 23.1.2 i686-pc-windows-msvc

AT&T syntax clang --target=i686-pc-windows-msvc -march=pentium4 -O2 -fno-asynchronous-unwind-tables -S cxx-this.cpp

"?add@Counter@@QAEHH@Z":
        movl    (%ecx), %eax
        addl    4(%esp), %eax
        movl    %eax, (%ecx)
        retl    $4

Intel syntax clang --target=i686-pc-windows-msvc -march=pentium4 -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-this.cpp

"?add@Counter@@QAEHH@Z":
        mov     eax, dword ptr [ecx]
        add     eax, dword ptr [esp + 4]
        mov     dword ptr [ecx], eax
        ret     4

Name mangling

C++ allows several functions of one name, in different namespaces and classes and with different parameters, so the name the linker sees encodes all of that. The two ABIs encode it differently, and a name from one never matches a name from the other.

The three calls name three functions. Itanium names start with _Z (with one more underscore on macOS, as for all C names there): N3geo4distE is geo::dist, RK a reference to const, and S_, S2_ refer back to parts already written. Microsoft names start with ?, with the name, then the scopes, and end in @Z.

cxx-mangling.cpp

// Overloads, a namespace and a template: each call names a different
// function, and the mangled names tell them apart.
namespace geo {
struct Point { int x, y; };
int dist(const Point &a, const Point &b);
int dist(int a, int b);
template <typename T> T scale(T v, int k);
}

int use(const geo::Point &p)
{
	return geo::dist(p, p) + geo::dist(1, 2) + geo::scale<long>(3, 4);
}

Clang 23.1.2 x86_64-linux-gnu

AT&T syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -S cxx-mangling.cpp

_Z3useRKN3geo5PointE:
        pushq   %rbp
        pushq   %rbx
        pushq   %rax
        movq    %rdi, %rsi
        callq   _ZN3geo4distERKNS_5PointES2_@PLT
        movl    %eax, %ebx
        movl    $1, %edi
        movl    $2, %esi
        callq   _ZN3geo4distEii@PLT
        movl    %eax, %ebp
        addl    %ebx, %ebp
        movl    $3, %edi
        movl    $4, %esi
        callq   _ZN3geo5scaleIlEET_S1_i@PLT
        addl    %ebp, %eax
        addq    $8, %rsp
        popq    %rbx
        popq    %rbp
        retq

Intel syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-mangling.cpp

_Z3useRKN3geo5PointE:
        push    rbp
        push    rbx
        push    rax
        mov     rsi, rdi
        call    _ZN3geo4distERKNS_5PointES2_@PLT
        mov     ebx, eax
        mov     edi, 1
        mov     esi, 2
        call    _ZN3geo4distEii@PLT
        mov     ebp, eax
        add     ebp, ebx
        mov     edi, 3
        mov     esi, 4
        call    _ZN3geo5scaleIlEET_S1_i@PLT
        add     eax, ebp
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret

Clang 23.1.2 x86_64-apple-macos11

AT&T syntax clang --target=x86_64-apple-macos11 -O2 -fno-asynchronous-unwind-tables -S cxx-mangling.cpp

__Z3useRKN3geo5PointE:
        pushq   %rbp
        movq    %rsp, %rbp
        pushq   %r14
        pushq   %rbx
        movq    %rdi, %rsi
        callq   __ZN3geo4distERKNS_5PointES2_
        movl    %eax, %ebx
        movl    $1, %edi
        movl    $2, %esi
        callq   __ZN3geo4distEii
        movl    %eax, %r14d
        addl    %ebx, %r14d
        movl    $3, %edi
        movl    $4, %esi
        callq   __ZN3geo5scaleIlEET_S1_i
        addl    %r14d, %eax
        popq    %rbx
        popq    %r14
        popq    %rbp
        retq

Intel syntax clang --target=x86_64-apple-macos11 -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-mangling.cpp

__Z3useRKN3geo5PointE:
        push    rbp
        mov     rbp, rsp
        push    r14
        push    rbx
        mov     rsi, rdi
        call    __ZN3geo4distERKNS_5PointES2_
        mov     ebx, eax
        mov     edi, 1
        mov     esi, 2
        call    __ZN3geo4distEii
        mov     r14d, eax
        add     r14d, ebx
        mov     edi, 3
        mov     esi, 4
        call    __ZN3geo5scaleIlEET_S1_i
        add     eax, r14d
        pop     rbx
        pop     r14
        pop     rbp
        ret

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -S cxx-mangling.cpp

"?use@@YAHAEBUPoint@geo@@@Z":
        pushq   %rsi
        pushq   %rdi
        subq    $40, %rsp
        movq    %rcx, %rdx
        callq   "?dist@geo@@YAHAEBUPoint@1@0@Z"
        movl    %eax, %esi
        movl    $1, %ecx
        movl    $2, %edx
        callq   "?dist@geo@@YAHHH@Z"
        movl    %eax, %edi
        addl    %esi, %edi
        movl    $3, %ecx
        movl    $4, %edx
        callq   "??$scale@J@geo@@YAJJH@Z"
        addl    %edi, %eax
        addq    $40, %rsp
        popq    %rdi
        popq    %rsi
        retq

Intel syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-mangling.cpp

"?use@@YAHAEBUPoint@geo@@@Z":
        push    rsi
        push    rdi
        sub     rsp, 40
        mov     rdx, rcx
        call    "?dist@geo@@YAHAEBUPoint@1@0@Z"
        mov     esi, eax
        mov     ecx, 1
        mov     edx, 2
        call    "?dist@geo@@YAHHH@Z"
        mov     edi, eax
        add     edi, esi
        mov     ecx, 3
        mov     edx, 4
        call    "??$scale@J@geo@@YAJJH@Z"
        add     eax, edi
        add     rsp, 40
        pop     rdi
        pop     rsi
        ret

The Itanium name of an ordinary function encodes its parameters but not its return type; only the names of template functions include it, like T_ in _ZN3geo5scaleIlEET_S1_i, where IlE is the template argument long. Microsoft’s names encode the return type and the calling convention of every function. Tools turn the names back into declarations: c++filt or llvm-cxxfilt for Itanium names, and Microsoft’s undname for its own.

Virtual tables

An object of a class with virtual functions starts with a pointer to its class’s table of virtual functions, and a virtual call loads the function from it. The two ABIs lay the tables out differently:

Virtual tables in the two ABIs.
Itanium C++ ABIMicrosoft C++ ABI
Before the functionsthe offset to the top of the object, then the type informationa pointer to the complete object locator, which leads to the type information
The object points tothe first function, after those two entriesthe first function
Virtual destructortwo entries: the complete object destructor and the deleting destructorone entry: the vector deleting destructor, which takes flags
Emitted inthe object file that defines the key function, if the class has oneevery object file that needs it, merged by the linker
Itanium: _ZTV6Square holds 0, the type information _ZTI6Square, the two destructors, area and sides; make_square stores _ZTV6Square+16, and area_of calls through 16(%rax), the third function. Microsoft: ??_7Square@@6B@ is defined 8 bytes into a block whose first word points to the complete object locator ??_R4Square@@6B@; area is the second entry, at 8(%rax), after the deleting destructor.

cxx-vtable.cpp

// A class with virtual functions, one of them defined here, an object
// of it made here, and a virtual call.
struct Shape {
	virtual ~Shape();
	virtual int area() const = 0;
	virtual int sides() const { return 0; }
};

struct Square : Shape {
	int side = 1;
	int area() const override;
	int sides() const override { return 4; }
};

int Square::area() const
{
	return side * side;
}

Shape *make_square()
{
	return new Square;
}

int area_of(const Shape &s)
{
	return s.area();
}

Clang 23.1.2 x86_64-linux-gnu

AT&T syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -S cxx-vtable.cpp

_ZNK6Square4areaEv:
        movl    8(%rdi), %eax
        imull   %eax, %eax
        retq

_Z11make_squarev:
        pushq   %rax
        movl    $16, %edi
        callq   _Znwm@PLT
        leaq    _ZTV6Square+16(%rip), %rcx
        movq    %rcx, (%rax)
        movl    $1, 8(%rax)
        popq    %rcx
        retq

_Z7area_ofRK5Shape:
        movq    (%rdi), %rax
        jmpq    *16(%rax)

_ZN6SquareD0Ev:
        pushq   %rbx
        movq    %rdi, %rbx
        callq   _ZN5ShapeD2Ev@PLT
        movl    $16, %esi
        movq    %rbx, %rdi
        popq    %rbx
        jmp     _ZdlPvm@PLT

_ZNK6Square5sidesEv:
        movl    $4, %eax
        retq

_ZTV6Square:
        .quad   0
        .quad   _ZTI6Square
        .quad   _ZN5ShapeD2Ev
        .quad   _ZN6SquareD0Ev
        .quad   _ZNK6Square4areaEv
        .quad   _ZNK6Square5sidesEv

_ZTI6Square:
        .quad   _ZTVN10__cxxabiv120__si_class_type_infoE+16
        .quad   _ZTS6Square
        .quad   _ZTI5Shape

_ZTS6Square:
        .asciz  "6Square"

Intel syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-vtable.cpp

_ZNK6Square4areaEv:
        mov     eax, dword ptr [rdi + 8]
        imul    eax, eax
        ret

_Z11make_squarev:
        push    rax
        mov     edi, 16
        call    _Znwm@PLT
        lea     rcx, [rip + _ZTV6Square+16]
        mov     qword ptr [rax], rcx
        mov     dword ptr [rax + 8], 1
        pop     rcx
        ret

_Z7area_ofRK5Shape:
        mov     rax, qword ptr [rdi]
        jmp     qword ptr [rax + 16]

_ZN6SquareD0Ev:
        push    rbx
        mov     rbx, rdi
        call    _ZN5ShapeD2Ev@PLT
        mov     esi, 16
        mov     rdi, rbx
        pop     rbx
        jmp     _ZdlPvm@PLT

_ZNK6Square5sidesEv:
        mov     eax, 4
        ret

_ZTV6Square:
        .quad   0
        .quad   _ZTI6Square
        .quad   _ZN5ShapeD2Ev
        .quad   _ZN6SquareD0Ev
        .quad   _ZNK6Square4areaEv
        .quad   _ZNK6Square5sidesEv

_ZTI6Square:
        .quad   _ZTVN10__cxxabiv120__si_class_type_infoE+16
        .quad   _ZTS6Square
        .quad   _ZTI5Shape

_ZTS6Square:
        .asciz  "6Square"

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -S cxx-vtable.cpp

"?area@Square@@UEBAHXZ":
        movl    8(%rcx), %eax
        imull   %eax, %eax
        retq

"?make_square@@YAPEAUShape@@XZ":
        subq    $40, %rsp
        movl    $16, %ecx
        callq   "??2@YAPEAX_K@Z"
        leaq    "??_7Square@@6B@"(%rip), %rcx
        movq    %rcx, (%rax)
        movl    $1, 8(%rax)
        addq    $40, %rsp
        retq

"?area_of@@YAHAEBUShape@@@Z":
        movq    (%rcx), %rax
        rex64 jmpq      *8(%rax)

"?sides@Square@@UEBAHXZ":
        movl    $4, %eax
        retq

"?sides@Shape@@UEBAHXZ":
        xorl    %eax, %eax
        retq

"??_GShape@@UEAAPEAXI@Z":
        ud2

"??_GSquare@@UEAAPEAXI@Z":
        pushq   %rsi
        pushq   %rdi
        subq    $40, %rsp
        movl    %edx, %edi
        movq    %rcx, %rsi
        callq   "??1Shape@@UEAA@XZ"
        testb   $1, %dil
        je      .LBB6_2
        movl    $16, %edx
        movq    %rsi, %rcx
        callq   "??3@YAXPEAX_K@Z"
.LBB6_2:
        movq    %rsi, %rax
        addq    $40, %rsp
        popq    %rdi
        popq    %rsi
        retq

.L__unnamed_1:
        .quad   "??_R4Square@@6B@"
        .quad   "??_ESquare@@UEAAPEAXI@Z"
        .quad   "?area@Square@@UEBAHXZ"
        .quad   "?sides@Square@@UEBAHXZ"

"??_R4Square@@6B@":
        .long   1
        .long   0
        .long   0
        .long   "??_R0?AUSquare@@@8"@IMGREL
        .long   "??_R3Square@@8"@IMGREL
        .long   "??_R4Square@@6B@"@IMGREL

"??_R0?AUSquare@@@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".?AUSquare@@"
        .zero   3

"??_R3Square@@8":
        .long   0
        .long   0
        .long   2
        .long   "??_R2Square@@8"@IMGREL

"??_R2Square@@8":
        .long   "??_R1A@?0A@EA@Square@@8"@IMGREL
        .long   "??_R1A@?0A@EA@Shape@@8"@IMGREL
        .long   0

"??_R1A@?0A@EA@Square@@8":
        .long   "??_R0?AUSquare@@@8"@IMGREL
        .long   1
        .long   0
        .long   4294967295
        .long   0
        .long   64
        .long   "??_R3Square@@8"@IMGREL

"??_R1A@?0A@EA@Shape@@8":
        .long   "??_R0?AUShape@@@8"@IMGREL
        .long   0
        .long   0
        .long   4294967295
        .long   0
        .long   64
        .long   "??_R3Shape@@8"@IMGREL

"??_R0?AUShape@@@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".?AUShape@@"
        .zero   4

"??_R3Shape@@8":
        .long   0
        .long   0
        .long   1
        .long   "??_R2Shape@@8"@IMGREL

"??_R2Shape@@8":
        .long   "??_R1A@?0A@EA@Shape@@8"@IMGREL
        .long   0

"??_R4Shape@@6B@":
        .long   1
        .long   0
        .long   0
        .long   "??_R0?AUShape@@@8"@IMGREL
        .long   "??_R3Shape@@8"@IMGREL
        .long   "??_R4Shape@@6B@"@IMGREL
"??_7Square@@6B@" = .L__unnamed_1+8
"??_ESquare@@UEAAPEAXI@Z" = "??_GSquare@@UEAAPEAXI@Z"

Intel syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-vtable.cpp

"?area@Square@@UEBAHXZ":
        mov     eax, dword ptr [rcx + 8]
        imul    eax, eax
        ret

"?make_square@@YAPEAUShape@@XZ":
        sub     rsp, 40
        mov     ecx, 16
        call    "??2@YAPEAX_K@Z"
        lea     rcx, [rip + "??_7Square@@6B@"]
        mov     qword ptr [rax], rcx
        mov     dword ptr [rax + 8], 1
        add     rsp, 40
        ret

"?area_of@@YAHAEBUShape@@@Z":
        mov     rax, qword ptr [rcx]
        rex64 jmp       qword ptr [rax + 8]

"?sides@Square@@UEBAHXZ":
        mov     eax, 4
        ret

"?sides@Shape@@UEBAHXZ":
        xor     eax, eax
        ret

"??_GShape@@UEAAPEAXI@Z":
        ud2

"??_GSquare@@UEAAPEAXI@Z":
        push    rsi
        push    rdi
        sub     rsp, 40
        mov     edi, edx
        mov     rsi, rcx
        call    "??1Shape@@UEAA@XZ"
        test    dil, 1
        je      .LBB6_2
        mov     edx, 16
        mov     rcx, rsi
        call    "??3@YAXPEAX_K@Z"
.LBB6_2:
        mov     rax, rsi
        add     rsp, 40
        pop     rdi
        pop     rsi
        ret

.L__unnamed_1:
        .quad   "??_R4Square@@6B@"
        .quad   "??_ESquare@@UEAAPEAXI@Z"
        .quad   "?area@Square@@UEBAHXZ"
        .quad   "?sides@Square@@UEBAHXZ"

"??_R4Square@@6B@":
        .long   1
        .long   0
        .long   0
        .long   "??_R0?AUSquare@@@8"@IMGREL
        .long   "??_R3Square@@8"@IMGREL
        .long   "??_R4Square@@6B@"@IMGREL

"??_R0?AUSquare@@@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".?AUSquare@@"
        .zero   3

"??_R3Square@@8":
        .long   0
        .long   0
        .long   2
        .long   "??_R2Square@@8"@IMGREL

"??_R2Square@@8":
        .long   "??_R1A@?0A@EA@Square@@8"@IMGREL
        .long   "??_R1A@?0A@EA@Shape@@8"@IMGREL
        .long   0

"??_R1A@?0A@EA@Square@@8":
        .long   "??_R0?AUSquare@@@8"@IMGREL
        .long   1
        .long   0
        .long   4294967295
        .long   0
        .long   64
        .long   "??_R3Square@@8"@IMGREL

"??_R1A@?0A@EA@Shape@@8":
        .long   "??_R0?AUShape@@@8"@IMGREL
        .long   0
        .long   0
        .long   4294967295
        .long   0
        .long   64
        .long   "??_R3Shape@@8"@IMGREL

"??_R0?AUShape@@@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".?AUShape@@"
        .zero   4

"??_R3Shape@@8":
        .long   0
        .long   0
        .long   1
        .long   "??_R2Shape@@8"@IMGREL

"??_R2Shape@@8":
        .long   "??_R1A@?0A@EA@Shape@@8"@IMGREL
        .long   0

"??_R4Shape@@6B@":
        .long   1
        .long   0
        .long   0
        .long   "??_R0?AUShape@@@8"@IMGREL
        .long   "??_R3Shape@@8"@IMGREL
        .long   "??_R4Shape@@6B@"@IMGREL
"??_7Square@@6B@" = .L__unnamed_1+8
"??_ESquare@@UEAAPEAXI@Z" = "??_GSquare@@UEAAPEAXI@Z"

The key function of a class, in the Itanium C++ ABI, is its first virtual function that is neither pure nor inline where the class is defined; here Square::area. The table goes into the object file that defines it, once for the whole program. Microsoft’s vftable goes into every object file that creates such an object, in a COMDAT section, and the linker keeps one copy.

Member function pointers

A pointer to a member function must handle virtual functions, whose address depends on the object, and classes with several bases, where this must be adjusted. The Itanium C++ ABI always uses two words: the function’s address, or 1 plus the offset of its entry in the virtual table, and the adjustment of this. An odd first word marks a virtual function, since the ABI relies on member functions starting at even addresses.

Microsoft’s representation depends on the class’s inheritance: with single inheritance, a pointer to a member function is just the address of a function. For a virtual function that address is a thunk, which makes the virtual call. Multiple and virtual inheritance add fields, and a class that is not yet defined gets the largest form.

Itanium: invoke adds the adjustment in RDX to this, tests bit 0 of the first word and, if it is set, loads the function from the table; pick returns the pair in RAX and RDX, 1 for size (entry 0, plus 1). Such pointers take 16 bytes, for any class. Microsoft: invoke just jumps to the pointer, pick returns ??_9Widget@@$BA@AA, a thunk that calls entry 0, and the pointer takes 8 bytes; for the undefined class Later, 24.

cxx-member-pointer.cpp

// Pointers to member functions: calling one, taking one of a virtual
// and of a non-virtual function, and their sizes.
struct Widget {
	int value;
	int get();
	virtual int size();
};

typedef int (Widget::*Method)();

int invoke(Widget *w, Method m)
{
	return (w->*m)();
}

Method pick(bool virt)
{
	return virt ? &Widget::size : &Widget::get;
}

struct Later;
int method_size = sizeof(Method);
int later_size = sizeof(int (Later::*)());

Clang 23.1.2 x86_64-linux-gnu

AT&T syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -S cxx-member-pointer.cpp

_Z6invokeP6WidgetMS_FivE:
        addq    %rdx, %rdi
        testb   $1, %sil
        je      .LBB0_2
        movq    (%rdi), %rax
        movq    -1(%rax,%rsi), %rsi
.LBB0_2:
        jmpq    *%rsi

_Z4pickb:
        movl    $1, %eax
        testl   %edi, %edi
        jne     .LBB1_2
        movq    _ZN6Widget3getEv@GOTPCREL(%rip), %rax
.LBB1_2:
        xorl    %edx, %edx
        retq

method_size:
        .long   16

later_size:
        .long   16

Intel syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-member-pointer.cpp

_Z6invokeP6WidgetMS_FivE:
        add     rdi, rdx
        test    sil, 1
        je      .LBB0_2
        mov     rax, qword ptr [rdi]
        mov     rsi, qword ptr [rax + rsi - 1]
.LBB0_2:
        jmp     rsi

_Z4pickb:
        mov     eax, 1
        test    edi, edi
        jne     .LBB1_2
        mov     rax, qword ptr [rip + _ZN6Widget3getEv@GOTPCREL]
.LBB1_2:
        xor     edx, edx
        ret

method_size:
        .long   16

later_size:
        .long   16

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -S cxx-member-pointer.cpp

"?invoke@@YAHPEAUWidget@@P81@EAAHXZ@Z":
        rex64 jmpq      *%rdx

"?pick@@YAP8Widget@@EAAHXZ_N@Z":
        leaq    "??_9Widget@@$BA@AA"(%rip), %rdx
        leaq    "?get@Widget@@QEAAHXZ"(%rip), %rax
        testb   %cl, %cl
        cmovneq %rdx, %rax
        retq

"??_9Widget@@$BA@AA":
        movq    (%rcx), %rax
        movq    (%rax), %rax
        rex64 jmpq      *%rax

"?method_size@@3HA":
        .long   8

"?later_size@@3HA":
        .long   24

Intel syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -masm=intel -S cxx-member-pointer.cpp

"?invoke@@YAHPEAUWidget@@P81@EAAHXZ@Z":
        rex64 jmp       rdx

"?pick@@YAP8Widget@@EAAHXZ_N@Z":
        lea     rdx, [rip + "??_9Widget@@$BA@AA"]
        lea     rax, [rip + "?get@Widget@@QEAAHXZ"]
        test    cl, cl
        cmovne  rax, rdx
        ret

"??_9Widget@@$BA@AA":
        mov     rax, qword ptr [rcx]
        mov     rax, qword ptr [rax]
        rex64 jmp       rax

"?method_size@@3HA":
        .long   8

"?later_size@@3HA":
        .long   24

Exceptions

In the Itanium C++ ABI, throw allocates the exception with __cxa_allocate_exception and passes it to __cxa_throw with its type information. __cxa_throw hands it to the unwind library of the psABI, which walks the frames and calls each function’s personality routine, for C++ __gxx_personality_v0. The routine reads the function’s table of call sites and catch clauses, its language-specific data area or LSDA, and decides whether the function catches the exception. A catch block calls __cxa_begin_catch for the exception object, and __cxa_end_catch when it is done. Nothing runs when the program enters a try block.

.cfi_personality and .cfi_lsda point the unwind information of safe_parse at the personality routine and at its LSDA: a call site from .Ltmp0 to .Ltmp1 that lands at .Ltmp2 with action 1, which catches the type _ZTIi, int. For MinGW-w64, Clang uses the same runtime functions and tables, but the exception travels through Windows’ unwinding: __gxx_personality_seh0 is the handler of the function’s .xdata.

cxx-exceptions.cpp

// Throwing an int, and catching it around a call.
int parse(const char *s);

int safe_parse(const char *s)
{
	try {
		return parse(s);
	} catch (int code) {
		return -code;
	}
}

void fail(int code)
{
	throw code;
}

Clang 23.1.2 x86_64-linux-gnu

AT&T syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -S cxx-exceptions.cpp

_Z10safe_parsePKc:
.Lfunc_begin0:
        .cfi_startproc
        .cfi_personality 155, DW.ref.__gxx_personality_v0
        .cfi_lsda 27, .Lexception0
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset %rbx, -16
.Ltmp0:
        callq   _Z5parsePKc@PLT
.Ltmp1:
        popq    %rbx
        .cfi_def_cfa_offset 8
        retq
        .cfi_def_cfa_offset 16
.Ltmp2:
        movq    %rax, %rdi
        callq   __cxa_begin_catch@PLT
        xorl    %ebx, %ebx
        subl    (%rax), %ebx
        callq   __cxa_end_catch@PLT
        movl    %ebx, %eax
        popq    %rbx
        .cfi_def_cfa_offset 8
        retq
.Lfunc_end0:
        .cfi_endproc

GCC_except_table0:
.Lexception0:
        .byte   255
        .byte   155
        .uleb128 .Lttbase0-.Lttbaseref0
.Lttbaseref0:
        .byte   1
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0
        .uleb128 .Ltmp1-.Ltmp0
        .uleb128 .Ltmp2-.Lfunc_begin0
        .byte   1
        .uleb128 .Ltmp1-.Lfunc_begin0
        .uleb128 .Lfunc_end0-.Ltmp1
        .byte   0
        .byte   0
.Lcst_end0:
        .byte   1
        .byte   0
.Ltmp3:
        .long   .L_ZTIi.DW.stub-.Ltmp3
.Lttbase0:
_Z4faili:
        .cfi_startproc
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset %rbx, -16
        movl    %edi, %ebx
        movl    $4, %edi
        callq   __cxa_allocate_exception@PLT
        movl    %ebx, (%rax)
        movq    _ZTIi@GOTPCREL(%rip), %rsi
        movq    %rax, %rdi
        xorl    %edx, %edx
        callq   __cxa_throw@PLT
        .cfi_endproc

.L_ZTIi.DW.stub:
        .quad   _ZTIi

DW.ref.__gxx_personality_v0:
        .quad   __gxx_personality_v0

Intel syntax clang --target=x86_64-linux-gnu -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -masm=intel -S cxx-exceptions.cpp

_Z10safe_parsePKc:
.Lfunc_begin0:
        .cfi_startproc
        .cfi_personality 155, DW.ref.__gxx_personality_v0
        .cfi_lsda 27, .Lexception0
        push    rbx
        .cfi_def_cfa_offset 16
        .cfi_offset rbx, -16
.Ltmp0:
        call    _Z5parsePKc@PLT
.Ltmp1:
        pop     rbx
        .cfi_def_cfa_offset 8
        ret
        .cfi_def_cfa_offset 16
.Ltmp2:
        mov     rdi, rax
        call    __cxa_begin_catch@PLT
        xor     ebx, ebx
        sub     ebx, dword ptr [rax]
        call    __cxa_end_catch@PLT
        mov     eax, ebx
        pop     rbx
        .cfi_def_cfa_offset 8
        ret
.Lfunc_end0:
        .cfi_endproc

GCC_except_table0:
.Lexception0:
        .byte   255
        .byte   155
        .uleb128 .Lttbase0-.Lttbaseref0
.Lttbaseref0:
        .byte   1
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0
        .uleb128 .Ltmp1-.Ltmp0
        .uleb128 .Ltmp2-.Lfunc_begin0
        .byte   1
        .uleb128 .Ltmp1-.Lfunc_begin0
        .uleb128 .Lfunc_end0-.Ltmp1
        .byte   0
        .byte   0
.Lcst_end0:
        .byte   1
        .byte   0
.Ltmp3:
        .long   .L_ZTIi.DW.stub-.Ltmp3
.Lttbase0:
_Z4faili:
        .cfi_startproc
        push    rbx
        .cfi_def_cfa_offset 16
        .cfi_offset rbx, -16
        mov     ebx, edi
        mov     edi, 4
        call    __cxa_allocate_exception@PLT
        mov     dword ptr [rax], ebx
        mov     rsi, qword ptr [rip + _ZTIi@GOTPCREL]
        mov     rdi, rax
        xor     edx, edx
        call    __cxa_throw@PLT
        .cfi_endproc

.L_ZTIi.DW.stub:
        .quad   _ZTIi

DW.ref.__gxx_personality_v0:
        .quad   __gxx_personality_v0

Clang 23.1.2 x86_64-w64-windows-gnu

AT&T syntax clang --target=x86_64-w64-windows-gnu -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -S cxx-exceptions.cpp

_Z10safe_parsePKc:
.Lfunc_begin0:
.seh_proc _Z10safe_parsePKc
        .seh_handler __gxx_personality_seh0, @unwind, @except
        pushq   %rsi
        .seh_pushreg %rsi
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
.Ltmp0:
        callq   _Z5parsePKc
        nop
.Ltmp1:
.LBB0_2:
        .seh_startepilogue
        addq    $32, %rsp
        popq    %rsi
        .seh_endepilogue
        retq
.Ltmp2:
        movq    %rax, %rcx
        callq   __cxa_begin_catch
        xorl    %esi, %esi
        subl    (%rax), %esi
        callq   __cxa_end_catch
        movl    %esi, %eax
        jmp     .LBB0_2
.Lfunc_end0:
        .seh_handlerdata
        .seh_endproc

GCC_except_table0:
.Lexception0:
        .byte   255
        .byte   0
        .uleb128 .Lttbase0-.Lttbaseref0
.Lttbaseref0:
        .byte   1
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0
        .uleb128 .Ltmp1-.Ltmp0
        .uleb128 .Ltmp2-.Lfunc_begin0
        .byte   1
        .uleb128 .Ltmp1-.Lfunc_begin0
        .uleb128 .Lfunc_end0-.Ltmp1
        .byte   0
        .byte   0
.Lcst_end0:
        .byte   1
        .byte   0
        .quad   _ZTIi
.Lttbase0:
_Z4faili:
.seh_proc _Z4faili
        pushq   %rsi
        .seh_pushreg %rsi
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        movl    %ecx, %esi
        movl    $4, %ecx
        callq   __cxa_allocate_exception
        movl    %esi, (%rax)
        movq    .refptr._ZTIi(%rip), %rdx
        movq    %rax, %rcx
        xorl    %r8d, %r8d
        callq   __cxa_throw
        int3
        .seh_endproc

.refptr._ZTIi:
        .quad   _ZTIi

Intel syntax clang --target=x86_64-w64-windows-gnu -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -masm=intel -S cxx-exceptions.cpp

_Z10safe_parsePKc:
.Lfunc_begin0:
.seh_proc _Z10safe_parsePKc
        .seh_handler __gxx_personality_seh0, @unwind, @except
        push    rsi
        .seh_pushreg rsi
        sub     rsp, 32
        .seh_stackalloc 32
        .seh_endprologue
.Ltmp0:
        call    _Z5parsePKc
        nop
.Ltmp1:
.LBB0_2:
        .seh_startepilogue
        add     rsp, 32
        pop     rsi
        .seh_endepilogue
        ret
.Ltmp2:
        mov     rcx, rax
        call    __cxa_begin_catch
        xor     esi, esi
        sub     esi, dword ptr [rax]
        call    __cxa_end_catch
        mov     eax, esi
        jmp     .LBB0_2
.Lfunc_end0:
        .seh_handlerdata
        .seh_endproc

GCC_except_table0:
.Lexception0:
        .byte   255
        .byte   0
        .uleb128 .Lttbase0-.Lttbaseref0
.Lttbaseref0:
        .byte   1
        .uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
        .uleb128 .Ltmp0-.Lfunc_begin0
        .uleb128 .Ltmp1-.Ltmp0
        .uleb128 .Ltmp2-.Lfunc_begin0
        .byte   1
        .uleb128 .Ltmp1-.Lfunc_begin0
        .uleb128 .Lfunc_end0-.Ltmp1
        .byte   0
        .byte   0
.Lcst_end0:
        .byte   1
        .byte   0
        .quad   _ZTIi
.Lttbase0:
_Z4faili:
.seh_proc _Z4faili
        push    rsi
        .seh_pushreg rsi
        sub     rsp, 32
        .seh_stackalloc 32
        .seh_endprologue
        mov     esi, ecx
        mov     ecx, 4
        call    __cxa_allocate_exception
        mov     dword ptr [rax], esi
        mov     rdx, qword ptr [rip + .refptr._ZTIi]
        mov     rcx, rax
        xor     r8d, r8d
        call    __cxa_throw
        int3
        .seh_endproc

.refptr._ZTIi:
        .quad   _ZTIi

Microsoft’s C++ exceptions are built on the structured exception handling of Windows. throw calls _CxxThrowException with the object and a description of its type and of the types it can be caught as. On x64 the handler of a function with try, __CxxFrameHandler3, reads tables that map the function’s code to states and states to try blocks and their catch clauses, and each catch block is compiled as a small function of its own. On 32-bit Windows the same handler is registered in the chain at FS:0 on entry to the function.

fail passes _TI1H, which leads through _CTA1H and _CT??_R0H@84 to the type descriptor of int, ??_R0H@8. The tables of safe_parse start at $cppxdata$: the try block, its catch clause for ??_R0H@8 handled by the funclet ?catch$2@..., and the map from code addresses to states. The funclet returns the address where safe_parse continues, .LBB0_1.

cxx-exceptions.cpp

// Throwing an int, and catching it around a call.
int parse(const char *s);

int safe_parse(const char *s)
{
	try {
		return parse(s);
	} catch (int code) {
		return -code;
	}
}

void fail(int code)
{
	throw code;
}

Clang 23.1.2 x86_64-pc-windows-msvc

AT&T syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -S cxx-exceptions.cpp

"?safe_parse@@YAHPEBD@Z":
.Lfunc_begin0:
.seh_proc "?safe_parse@@YAHPEBD@Z"
        .seh_handler __CxxFrameHandler3, @unwind, @except
        pushq   %rbp
        .seh_pushreg %rbp
        subq    $64, %rsp
        .seh_stackalloc 64
        leaq    64(%rsp), %rbp
        .seh_setframe %rbp, 64
        .seh_endprologue
        movq    $-2, -16(%rbp)
.Ltmp0:
        callq   "?parse@@YAHPEBD@Z"
        movl    %eax, -20(%rbp)
.Ltmp1:
.LBB0_1:
        movl    -20(%rbp), %eax
        .seh_startepilogue
        addq    $64, %rsp
        popq    %rbp
        .seh_endepilogue
        retq
        .seh_handlerdata
        .long   "$cppxdata$?safe_parse@@YAHPEBD@Z"@IMGREL
        .seh_endproc

"?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA":
.seh_proc "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"
        .seh_handler __CxxFrameHandler3, @unwind, @except
        movq    %rdx, 16(%rsp)
        pushq   %rbp
        .seh_pushreg %rbp
        subq    $32, %rsp
        .seh_stackalloc 32
        leaq    64(%rdx), %rbp
        .seh_endprologue
        xorl    %eax, %eax
        subl    -4(%rbp), %eax
        movl    %eax, -20(%rbp)
        leaq    .LBB0_1(%rip), %rax
        .seh_startepilogue
        addq    $32, %rsp
        popq    %rbp
        .seh_endepilogue
        retq
        .seh_handlerdata
        .long   "$cppxdata$?safe_parse@@YAHPEBD@Z"@IMGREL
        .seh_endproc

"$cppxdata$?safe_parse@@YAHPEBD@Z":
        .long   429065506
        .long   2
        .long   "$stateUnwindMap$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   1
        .long   "$tryMap$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   4
        .long   "$ip2state$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   48
        .long   0
        .long   1
"$stateUnwindMap$?safe_parse@@YAHPEBD@Z":
        .long   -1
        .long   0
        .long   -1
        .long   0
"$tryMap$?safe_parse@@YAHPEBD@Z":
        .long   0
        .long   0
        .long   1
        .long   1
        .long   "$handlerMap$0$?safe_parse@@YAHPEBD@Z"@IMGREL
"$handlerMap$0$?safe_parse@@YAHPEBD@Z":
        .long   0
        .long   "??_R0H@8"@IMGREL
        .long   60
        .long   "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"@IMGREL
        .long   56
"$ip2state$?safe_parse@@YAHPEBD@Z":
        .long   .Lfunc_begin0@IMGREL
        .long   -1
        .long   .Ltmp0@IMGREL
        .long   0
        .long   .Ltmp1@IMGREL
        .long   -1
        .long   "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"@IMGREL
        .long   1

"?fail@@YAXH@Z":
.seh_proc "?fail@@YAXH@Z"
        subq    $40, %rsp
        .seh_stackalloc 40
        .seh_endprologue
        movl    %ecx, 36(%rsp)
        leaq    _TI1H(%rip), %rdx
        leaq    36(%rsp), %rcx
        callq   _CxxThrowException
        int3
        .seh_endproc

"??_R0H@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".H"
        .zero   5

"_CT??_R0H@84":
        .long   1
        .long   "??_R0H@8"@IMGREL
        .long   0
        .long   4294967295
        .long   0
        .long   4
        .long   0

_CTA1H:
        .long   1
        .long   "_CT??_R0H@84"@IMGREL

_TI1H:
        .long   0
        .long   0
        .long   0
        .long   _CTA1H@IMGREL

Intel syntax clang --target=x86_64-pc-windows-msvc -O2 -fno-asynchronous-unwind-tables -fasynchronous-unwind-tables -masm=intel -S cxx-exceptions.cpp

"?safe_parse@@YAHPEBD@Z":
.Lfunc_begin0:
.seh_proc "?safe_parse@@YAHPEBD@Z"
        .seh_handler __CxxFrameHandler3, @unwind, @except
        push    rbp
        .seh_pushreg rbp
        sub     rsp, 64
        .seh_stackalloc 64
        lea     rbp, [rsp + 64]
        .seh_setframe rbp, 64
        .seh_endprologue
        mov     qword ptr [rbp - 16], -2
.Ltmp0:
        call    "?parse@@YAHPEBD@Z"
        mov     dword ptr [rbp - 20], eax
.Ltmp1:
.LBB0_1:
        mov     eax, dword ptr [rbp - 20]
        .seh_startepilogue
        add     rsp, 64
        pop     rbp
        .seh_endepilogue
        ret
        .seh_handlerdata
        .long   "$cppxdata$?safe_parse@@YAHPEBD@Z"@IMGREL
        .seh_endproc

"?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA":
.seh_proc "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"
        .seh_handler __CxxFrameHandler3, @unwind, @except
        mov     qword ptr [rsp + 16], rdx
        push    rbp
        .seh_pushreg rbp
        sub     rsp, 32
        .seh_stackalloc 32
        lea     rbp, [rdx + 64]
        .seh_endprologue
        xor     eax, eax
        sub     eax, dword ptr [rbp - 4]
        mov     dword ptr [rbp - 20], eax
        lea     rax, [rip + .LBB0_1]
        .seh_startepilogue
        add     rsp, 32
        pop     rbp
        .seh_endepilogue
        ret
        .seh_handlerdata
        .long   "$cppxdata$?safe_parse@@YAHPEBD@Z"@IMGREL
        .seh_endproc

"$cppxdata$?safe_parse@@YAHPEBD@Z":
        .long   429065506
        .long   2
        .long   "$stateUnwindMap$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   1
        .long   "$tryMap$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   4
        .long   "$ip2state$?safe_parse@@YAHPEBD@Z"@IMGREL
        .long   48
        .long   0
        .long   1
"$stateUnwindMap$?safe_parse@@YAHPEBD@Z":
        .long   -1
        .long   0
        .long   -1
        .long   0
"$tryMap$?safe_parse@@YAHPEBD@Z":
        .long   0
        .long   0
        .long   1
        .long   1
        .long   "$handlerMap$0$?safe_parse@@YAHPEBD@Z"@IMGREL
"$handlerMap$0$?safe_parse@@YAHPEBD@Z":
        .long   0
        .long   "??_R0H@8"@IMGREL
        .long   60
        .long   "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"@IMGREL
        .long   56
"$ip2state$?safe_parse@@YAHPEBD@Z":
        .long   .Lfunc_begin0@IMGREL
        .long   -1
        .long   .Ltmp0@IMGREL
        .long   0
        .long   .Ltmp1@IMGREL
        .long   -1
        .long   "?catch$2@?0??safe_parse@@YAHPEBD@Z@4HA"@IMGREL
        .long   1

"?fail@@YAXH@Z":
.seh_proc "?fail@@YAXH@Z"
        sub     rsp, 40
        .seh_stackalloc 40
        .seh_endprologue
        mov     dword ptr [rsp + 36], ecx
        lea     rdx, [rip + _TI1H]
        lea     rcx, [rsp + 36]
        call    _CxxThrowException
        int3
        .seh_endproc

"??_R0H@8":
        .quad   "??_7type_info@@6B@"
        .quad   0
        .asciz  ".H"
        .zero   5

"_CT??_R0H@84":
        .long   1
        .long   "??_R0H@8"@IMGREL
        .long   0
        .long   4294967295
        .long   0
        .long   4
        .long   0

_CTA1H:
        .long   1
        .long   "_CT??_R0H@84"@IMGREL

_TI1H:
        .long   0
        .long   0
        .long   0
        .long   _CTA1H@IMGREL

MSVC’s /EH option chooses what catch (...) catches: with /EHa, also the structured exceptions of the processor and the system, such as access violations; with /EHsc, only C++ exceptions.

Summary

The two C++ ABIs side by side.
Itanium C++ ABIMicrosoft C++ ABI
thisthe first argumentthe first argument; ECX on 32-bit x86
Names_Z...; no return type except for templates?...@Z; with return type and calling convention
Virtual tableoffset to top and type information before the functions; key functionlocator before the functions; COMDAT
Pointer to member functionalways two wordsone field to four, by inheritance
Exceptions__cxa_throw, personality routine and LSDA_CxxThrowException, __CxxFrameHandler3 and its tables

Sources

  1. Itanium C++ ABI: commit fae5e46c8614, 2026-01-20
  2. Itanium C++ ABI: Exception Handling: commit fae5e46c8614, 2026-01-20
  3. GCC 14.2 manual: Binary Compatibility: as published on 2026-09-25
  4. System V Application Binary Interface, AMD64 Architecture Processor Supplement, version 1.0: commit e1ce098331da, 2025-03-12
  5. Microsoft Learn: Decorated names: commit f70d88cd5da7, 2026-09-24
  6. Microsoft Learn: __thiscall: commit f70d88cd5da7, 2026-09-24
  7. Clang 23.1.2: clang/lib/CodeGen/MicrosoftCXXABI.cpp: commit 85ac56026243, 2026-09-20
  8. Microsoft Learn: Inheritance keywords: commit f70d88cd5da7, 2026-09-24
  9. Microsoft Learn: /vmb, /vmg (Representation method): commit f70d88cd5da7, 2026-09-24
  10. Microsoft Learn: /EH (Exception handling model): commit f70d88cd5da7, 2026-09-24
  11. Microsoft Learn: x64 exception handling: commit f70d88cd5da7, 2026-09-24
  12. LLVM 23.1.2: llvm/lib/Target/X86/X86WinEHState.cpp: commit 85ac56026243, 2026-09-20