GCC 的 nm 列出了 method 的多个条目
GCC's nm lists multiple entries for method
nm列出的单个方法有多个条目是否正常?我 运行 以下内容:
nm -C myObjectFile.o | grep MyObject::
并收到以下内容:
... stuff...
... stuff...
0000027e0 T MyObject::MyObject(MyDepend*)
0000027e0 T MyObject::MyObject(MyDepend*)
000000030 T MyObject::~MyObject()
000000000 T MyObject::~MyObject()
000000000 T MyObject::~MyObject()
000000060 T non-virtual thunk to MyObject::~MyObject()
000000020 T non-virtual thunk to MyObject::~MyObject()
这对我来说似乎是错误的。你觉得不对吗?如果是这样,您能否详细说明为什么它是错误的以及可能导致它的原因是什么?如果仅在某些情况下它是正确的,那么我将详细解释让我查看 nm 输出的问题,我们可以从那里开始。
在某些情况下,分解器会将不同的输入分解为相同的输出。有时这可能会有点混乱,但我认为已经完成了,因为在其他情况下它不那么混乱;例如,gdb 使用 demangler,这种方法可以让构造函数上的断点做正确的事情,而无需用户额外的努力。也许通过一些思考和工作,这里可能会有一些改进。
无论如何,这是一个简单的例子:
class K
{
K ();
virtual ~K();
};
K::K() { }
K::~K() { }
使用 -g
编译,然后 运行ning nm -C
显示与您的类似的结果:
$ 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
但是让我们看看如果我们 运行 普通 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
这里可以更清楚的看出底层符号的不同
由此我们可以进入C++ ABI that GCC follows;特别是关于修改构造函数和析构函数的部分。由于历史原因,这被称为 "Itanium" ABI,但它确实在所有平台上使用(可能有较小的变体)。
本部分解释了名称的含义,但您必须更深入地研究文档才能完全理解。基本思想是,在C++的实现中,构造函数和析构函数需要不同的入口点;这是通过为不同的入口点提供不同的符号来完成的。
nm列出的单个方法有多个条目是否正常?我 运行 以下内容:
nm -C myObjectFile.o | grep MyObject::
并收到以下内容:
... stuff...
... stuff...
0000027e0 T MyObject::MyObject(MyDepend*)
0000027e0 T MyObject::MyObject(MyDepend*)
000000030 T MyObject::~MyObject()
000000000 T MyObject::~MyObject()
000000000 T MyObject::~MyObject()
000000060 T non-virtual thunk to MyObject::~MyObject()
000000020 T non-virtual thunk to MyObject::~MyObject()
这对我来说似乎是错误的。你觉得不对吗?如果是这样,您能否详细说明为什么它是错误的以及可能导致它的原因是什么?如果仅在某些情况下它是正确的,那么我将详细解释让我查看 nm 输出的问题,我们可以从那里开始。
在某些情况下,分解器会将不同的输入分解为相同的输出。有时这可能会有点混乱,但我认为已经完成了,因为在其他情况下它不那么混乱;例如,gdb 使用 demangler,这种方法可以让构造函数上的断点做正确的事情,而无需用户额外的努力。也许通过一些思考和工作,这里可能会有一些改进。
无论如何,这是一个简单的例子:
class K
{
K ();
virtual ~K();
};
K::K() { }
K::~K() { }
使用 -g
编译,然后 运行ning nm -C
显示与您的类似的结果:
$ 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
但是让我们看看如果我们 运行 普通 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
这里可以更清楚的看出底层符号的不同
由此我们可以进入C++ ABI that GCC follows;特别是关于修改构造函数和析构函数的部分。由于历史原因,这被称为 "Itanium" ABI,但它确实在所有平台上使用(可能有较小的变体)。
本部分解释了名称的含义,但您必须更深入地研究文档才能完全理解。基本思想是,在C++的实现中,构造函数和析构函数需要不同的入口点;这是通过为不同的入口点提供不同的符号来完成的。