Интерпретировать символ COMDAT файла COFF как удобочитаемую сигнатуру функции
Я хочу интерпретировать символ COMDAT файла COFF Символ COMDAT
?make@DNameStatusNode@@SAPAV1@W4DNameStatus@@@Z
Как я могу интерпретировать это как
(public: static class DNameStatusNode * __cdecl DNameStatusNode::make(enum DNameStatus))
Благодарю.
1 ответ
Это будет "украшенное" (искаженное) имя функции C++, сгенерированное Visual Studio (и VS-совместимыми компиляторами Windows), а не символ COMDAT.
Самый простой способ - провести символ через UNDNAME.EXE
утилита, которая поставляется с Visual Studio. За исключением этого, вы можете использовать UnDecorateSymbolName()
функция в библиотеке Dbghelp.dll
или недокументированная внутренняя функция __unDName()
(что, насколько мне известно, это то, что UNDNAME
использует); Я предполагаю, что вы хотя бы немного знакомы с этой функцией, учитывая, что DName
является одним из его вспомогательных классов. [Обратите внимание, что хотя эти инструменты в основном точны, в некоторых случаях они дают сбой (например, указатель const
-ness, определенные символы C++/CLI или функционально-локальные классы, объявленные в extern "C"
функции (в том числе main()
).]
Если ничего не помогает, вы также можете попытаться раскрутить имя вручную, что потребует знакомства с самой схемой искажения; Если вы не знакомы с внутренней информацией MS, это может потребовать значительных экспериментов и / или исследований, но это наиболее точный способ. Есть несколько простых рекомендаций, которые могут помочь с этим:
- Имена почти всегда начинаются с ведущих
?
, Если нет, то?
будут предшествовать специальные модификаторы (такие как__imp_
за__declspec(dllimport)
или же?@
для CodeView), с правильным именем, начинающимся с?
, - После ведущих
?
, сегмент до@@
является квалифицированным именем сущности, разбитым на отдельные имена компонентов (сначала имя символа, затем каждое, содержащее имя области; область действия пространства имен и класса обрабатываются одинаково для этого этапа процесса искажения); за каждым из имен компонентов, составляющих квалифицированное имя, сразу же следует один@
, который действует как терминатор для этого имени, а полное имя завершается автономным@
(обычно создает двойной@@
). Прочитайте это справа налево, заменяя любой@
с оператором области::
и останавливаясь на втором@
в двойном@@
, [Обратите внимание, что есть также случаи, когда это правило не соблюдается, и что имена шаблонных сущностей действительно странные. Также обратите внимание, что когда пользовательский тип (enum, class, struct, union) встречается во время информации о типе, его квалифицированное имя будет использоваться в соответствии с обычными правилами квалифицированного именования, за исключением того, что 1) ему будет предшествовать идентификатор вместо знака вопроса 1 и 2) имя будет сокращено, если это возможно 2. ]- Некоторые специальные объекты (такие как операторы, внутренние вспомогательные функции и внутренние вспомогательные объекты) будут иметь специальные имена, которые принимают форму
?x
, гдеx
является цифрой или заглавной буквой, которой предшествуют 0-2 подчеркивания; обратите внимание, что эти имена действуют как специальные сокращения 2, и, как таковые, не заканчиваются ни одним@
, В связи с этим, специальные субъекты-члены будут иметь имя, подобное??_FCLS@@QAEXXZ
(закрытие конструктора по умолчанию дляclass ::CLS
), и специальные объекты, не являющиеся членами, будут иметь имена, оканчивающиеся одним@
вместо двойного@@
(такие как??_H@YGXPAXIHP6EPAX0@Z@Z
итератор векторного конструктора; Обратите внимание, что??_H@
это его полное имя, и все, что после этого является информацией о типе).
- Некоторые специальные объекты (такие как операторы, внутренние вспомогательные функции и внутренние вспомогательные объекты) будут иметь специальные имена, которые принимают форму
- Сегмент после
@@
содержит всю соответствующую информацию о типах, и ее очень трудно объяснить, не вдаваясь в подробности. Я бы предложил использовать ресурс, такой как "Соглашение о вызовах для различных компиляторов и операционных систем C++" Агнера Фога, PDF и / или страницу Викиверситета "Искаженное имя в Visual C++" в качестве ссылки; хотя их информация не на 100% точна, она достаточно точна, чтобы прочитать большинство искаженных имен, с которыми вы столкнетесь.
Надеюсь это поможет.
1: одно из следующего будет использоваться для указания типа UDT:
- Enum:
W4
[Обратите внимание, что это технически представляетenum : int
, но по какой-то причине компилятор искажает все типы перечислений какW4
и хранит информацию о базовых типах в другом месте.] - Учебный класс:
V
- Struct:
U
- Союз:
T
За ним последует квалифицированное имя UDT, которое заканчивается @@
по-прежнему.
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 встреченных имен, как имя, так и его окончание @
будет сокращено до цифры, представляющей это ранее использованное имя. Аббревиатуры индексируются нулем, а фактическое имя символа считается именем 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
сущности имеют внутренние имена, которые отличаются от аббревиатур. Как и в случае обычных сокращений, эти специальные сокращения расширяются до имени и его окончания @
; из-за этого за специальной аббревиатурой сразу же будет следовать либо завершающий квалифицированное имя второй @
или любыми содержащимися областями.
// 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).