我想解释 COFF 文件的 COMDAT 符号 COMDAT 符号是
?make@DNameStatusNode@@SAPAV1@W4DNameStatus@@@Z
我怎么能把它解释为
(public: static class DNameStatusNode * __cdecl DNameStatusNode::make(enum DNameStatus))
谢谢。
那将是由 Visual Studio(和与 VS 兼容的 Windows 编译器)生成的“修饰的”(损坏的)C++ 函数名称,而不是专门的 COMDAT 符号。
最简单的方法是通过UNDNAME.EXE
Visual Studio 附带的实用程序运行符号。除此之外,您可以使用UnDecorateSymbolName()
library 中的函数Dbghelp.dll
,或未记录的内部函数__unDName()
(据我所知,它是什么UNDNAME
用途);DName
考虑到这是它的帮助类之一,我假设您至少对这个函数有点熟悉。[请注意,虽然这些工具大多是准确的,但在少数情况下它们会动摇(例如指针const
性、某些 C++/CLI 符号或在extern "C"
函数(包括main()
)中声明的函数局部类。]
如果一切都失败了,您也可以尝试手动修改名称,这需要熟悉修改方案本身;如果您不了解 MS 内部信息,这可能需要大量的实验和/或研究,但这是最准确的方法。不过,有一些简单的指南可以帮助解决这个问题:
?
。如果不是,则?
将在前面加上特殊修饰符(例如__imp_
for__declspec(dllimport)
或?@
for CodeView),其名称正确以 . 开头?
。?
,直到并包括 的段@@
是实体的限定名称,分解为单独的组件名称(首先是符号名称,然后是每个包含范围的名称;名称空间范围和类范围在处理过程的这一步中被同等对待); 构成限定名称的每个组件名称后面紧跟一个 single @
,它充当该名称的终止符,而全名由一个独立名称终止@
(通常创建一个 double @@
)。从右到左阅读,用@
作用域运算符替换任何 single 并在 double::
中的第二个处停止。[请注意,也有不遵循此规则的情况,模板实体名称是@
@@
真的很奇怪。另请注意,当在类型信息期间遇到用户定义的类型(枚举、类、结构、联合)时,将根据正常的限定名修改规则使用其限定名,但以下情况除外:1)它前面会带有一个标识符而不是问号1和 2) 如果可能,名称将被缩写2。]
?x
为 x
请注意,这些名称充当特殊缩写2,因此,不会以单个 . 结尾@
。因此,特殊成员实体将具有类似的名称??_FCLS@@QAEXXZ
(默认构造函数闭包class ::CLS
),并且特殊的非成员实体将具有以单@
而不是双精度结尾的名称@@
(例如??_H@YGXPAXIHP6EPAX0@Z@Z
,向量构造函数迭代器;请注意,??_H@
它的完全-qualified name,之后的所有内容都是类型信息)。@@
就很难解释。我建议使用诸如 Agner Fog 的“不同 C++ 编译器和操作系统的调用约定”PDF 和/或 Wikiversity 页面“Visual C++ name mangling”之类的资源作为参考;虽然他们的信息不是 100% 准确,但它足以准确读取您会遇到的大多数错误名称。希望这可以帮助。
1 : 以下之一将用于指示 UDT 的类型:
W4
[请注意,这在技术上表示enum : int
,但由于某种原因,编译器将所有枚举类型破坏为W4
并将底层类型信息存储在其他地方。]V
U
T
@@
它后面是 UDT 的限定名称,它像往常一样以 a 结尾。
class CL; // Is: VCL@@
struct ST; // Is: UST@@
enum EN; // Is: W4EN@@
union UN; // Is: TUN@@
namespace X { class CL; } // Is: VCL@X@@
2:如果在修改符号时已经遇到 UDT 限定名称中的任何组件名称(无论是作为符号限定名称的一部分,还是作为参数限定名称的一部分(从左到右读取参数)),并且它是遇到的前 10 个名称之一,名称及其终止符@
都将缩写为代表先前使用的名称的数字。缩写是零索引的,符号的实际名称被计为 name 0
。
namespace Y {
void func(X::CL param);
// Is: ?func@Y@@YAXVCL@X@@@Z
}
namespace X {
void func(CL param);
// Is: ?func@Y@@YAXVCL@1@@Z
// "X@" is replaced with "1".
}
如前所述,某些特殊实体(运算符、某些内部辅助函数和某些内部辅助对象)也使用名称缩写规则,使用硬编码到编译器中的特殊缩写;有趣的是,大多数非operator
实体都有内部名称,与缩写不同。与普通缩写一样,这些特殊缩写扩展为名称及其终止@
;因此,特殊缩写后将紧跟限定名称终止的 second@
或任何包含范围。
// Containing scopes example, with 'scalar deleting destructor':
class CL {
public:
~CL();
};
CL::~CL() {} // Non-trivial destructor.
// If an instance of the above class is deleted with "delete", the compiler will create
// hidden member functions 'scalar deleting destructor' and 'vector deleting destructor'.
// The former will have this mangled symbol:
// ??_GCL@@QAEPAXI@Z
// Note that there's no '@' between '?_G' (function name) & 'CL@' (containing scope name).
// Global example, with 'vector constructor iterator':
class CL {
public:
CL();
};
CL::CL() {} // Non-trivial constructor.
CL cls[3]; // Create an array of class with non-trivial ctor.
// The compiler uses the 'vector constructor iterator' to create the array and initialise
// each instance.
// It has the mangled symbol:
// ??_H@YGXPAXIHP6EPAX0@Z@Z
// Note that there's no '@' between '?_H' (function name) & '@' (qualified name terminator).