In some cases the demangler will demangle different inputs to the same output. This can be mildly confusing at times but is done, I think, because in other cases it is less confusing; for example the demangler is used by gdb and this approach lets breakpoints on constructors do the right thing without additional effort by the user. Maybe some improvement is possible here with some thought and work.
Anyway, here is a simple example:
class K
{
K ();
virtual ~K();
};
K::K() { }
K::~K() { }
Compiling with -g
and then running nm -C
shows results similar to yours:
$ nm -C q.o
U operator delete(void*)
0000000000000000 T K::K()
0000000000000000 T K::K()
0000000000000048 T K::~K()
0000000000000018 T K::~K()
0000000000000018 T K::~K()
0000000000000000 V typeinfo for K
0000000000000000 V typeinfo name for K
0000000000000000 V vtable for K
U vtable for __cxxabiv1::__class_type_info
But let's see what happens if we run plain nm
:
$ nm q.o
U _ZdlPv
0000000000000000 T _ZN1KC1Ev
0000000000000000 T _ZN1KC2Ev
0000000000000048 T _ZN1KD0Ev
0000000000000018 T _ZN1KD1Ev
0000000000000018 T _ZN1KD2Ev
0000000000000000 V _ZTI1K
0000000000000000 V _ZTS1K
0000000000000000 V _ZTV1K
U _ZTVN10__cxxabiv117__class_type_infoE
Here we can see more clearly that the underlying symbols are different.
From this we can go to the C++ ABI that GCC follows; in particular to the section about mangling constructors and destructors. For historical reasons this is called the "Itanium" ABI, but really it is used (perhaps with minor variants) on all platforms.
This section explains the meanings of the names, though you'd have to dig deeper into the document to fully understand. The basic idea is that, in the implementation of C++, there is a need for different entry points to constructors and destructors; and this is done by providing different symbols for the different entry points.