Интерпретировать символ 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).
Другие вопросы по тегам