Date: Thu, 6 Jun 2024 21:25:30 +0100
On Thu, Jun 6, 2024 at 1:08 AM Thiago Macieira wrote:
>
> 1) on 32-bit MSVC, are constructors and destructors
> __cdecl or __thiscall?
It's literally only 32-Bit x86 that passes the 'this' pointer in
anything other than the position of the first parameter. No other
combination of instruction set and operating system does that. As for
whether it's __cdecl or __thiscall, it should be the same as for any
other member function.
> 2) on IA-64 C++ ABI, the base constructors (mangling "C2") have an extra
> parameter passed implicitly, which is a pointer to the virtual-table-in-
> construction (a "TC" symbol). There's no way that user code could ever call
> this constructor.
This hadn't crossed my mind. But I at least think that destructors
should have an address. They're only ever implemented as
"void(*)(void*)", right? (i.e. the sole argument is the 'this'
pointer). I tried compiling the following template function:
template<typename T>
void destroy(T &arg)
{
arg.~T();
}
with the T set to S:
struct S {
~S(void) __attribute__((noinline)) { std::cout << "goodbye\n"; }
};
And the assembler for "destroy<S>" came out as:
e9 db ff ff ff jmp 0xffffffffffffffe0
If I change it to a virtual destructor, it comes out as:
48 8b 07 mov rax,QWORD PTR [rdi]
ff 20 jmp QWORD PTR [rax]
which is equivalent to:
void destroy(S &arg)
{
auto const vtable = (void(**)(void*))&arg;
auto const pf = vtable[0];
pf(&arg);
}
I reckon on every CPU, operating system and compiler, destructors are
just functions that take a 'this' pointer and return void.
>
> 1) on 32-bit MSVC, are constructors and destructors
> __cdecl or __thiscall?
It's literally only 32-Bit x86 that passes the 'this' pointer in
anything other than the position of the first parameter. No other
combination of instruction set and operating system does that. As for
whether it's __cdecl or __thiscall, it should be the same as for any
other member function.
> 2) on IA-64 C++ ABI, the base constructors (mangling "C2") have an extra
> parameter passed implicitly, which is a pointer to the virtual-table-in-
> construction (a "TC" symbol). There's no way that user code could ever call
> this constructor.
This hadn't crossed my mind. But I at least think that destructors
should have an address. They're only ever implemented as
"void(*)(void*)", right? (i.e. the sole argument is the 'this'
pointer). I tried compiling the following template function:
template<typename T>
void destroy(T &arg)
{
arg.~T();
}
with the T set to S:
struct S {
~S(void) __attribute__((noinline)) { std::cout << "goodbye\n"; }
};
And the assembler for "destroy<S>" came out as:
e9 db ff ff ff jmp 0xffffffffffffffe0
If I change it to a virtual destructor, it comes out as:
48 8b 07 mov rax,QWORD PTR [rdi]
ff 20 jmp QWORD PTR [rax]
which is equivalent to:
void destroy(S &arg)
{
auto const vtable = (void(**)(void*))&arg;
auto const pf = vtable[0];
pf(&arg);
}
I reckon on every CPU, operating system and compiler, destructors are
just functions that take a 'this' pointer and return void.
Received on 2024-06-06 20:25:42