2013-09-15 3 views

ответ

4

WinAPI использует __stdcall соглашения о вызове. Вызывающий вызывает все аргументы в стеке справа налево, вызывающий их снова выталкивает для очистки стека, как правило, с помощью инструкции RET n.

Это антипод соглашения о вызове __cdecl, общего по умолчанию в коде C и C++, где вызывающий объект очищает стек, как правило, с инструкцией ADD ESP,n после CALL. Преимущество __stdcall заключается в том, что он генерирует более компактный код, а только одну команду очистки в вызываемой функции вместо многих для каждого вызова функции. Но один большой недостаток: это опасно.

Опасность скрывается в коде, который вызывает функцию, скомпилированную с устаревшим объявлением функции. Типично, когда функция была изменена добавлением аргумента, например. Это заканчивается очень плохо, помимо функции, пытающейся использовать аргумент, который недоступен, новая функция выставляет слишком много аргументов из стека. Это приводит к несбалансированности стека, в результате чего не только вызываемый пользователь терпит неудачу, но и вызывающий. Чрезвычайно трудно диагностировать.

Значит, они что-то сделали, они украсили название функции. Сначала с ведущим _underscore, как это делается для функций __cdecl. И добавлено @n, значение n является операндом команды RET в конце функции. Или, другими словами, количество байтов, принимаемых аргументами в стеке.

Это обеспечивает диагностику компоновщика, когда есть несоответствие, изменение функции foo(int) на foo(int, int), например, генерирует имя [email protected]. Код вызова, еще не перекомпилированный, будет искать функцию [email protected]. Компилятор не работает, он не может найти этот символ. Бедствия можно избежать.

+0

+1 Контрастность '__cdecl' и' __stdcall', чтобы вывести необходимость для украшений имен. Действительно хорошее объяснение, которое выходит за рамки *, что это такое *, и объясняет * почему *. – IInspectable

3

Это имя украшения с указанием общего размера аргументов функции:

имя следует за символом (@), а затем по количеству байтов (в десятичной системе) в списке аргументов.

(source)

+0

спасибо.Есть ли способ определить количество байтов? –

+0

Если это функция Windows API, вы можете найти прототип функции в [msdn] (http://msdn.microsoft.com/en-US/). Затем вы просто добавляете размеры аргументов. Например, [CreateThread] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453 (v = vs.85) .aspx) принимает шесть аргументов, и каждый из них имеет 4 байта в (это требует знаний о используемых типах). Таким образом, символ будет '_CreateThread @ 24' – Michael

+0

Спасибо, очень полезно. –

3

Название схемы украшения для C документирован в Format of a C Decorated Name. Декоративное имя, содержащее @ символа используется для __stdcall вызывающей конвенции:

__stdcall: Ведущее подчеркивание (_) и замыкающая знак (@) с последующим числом, обозначающее количество байт в списке параметров

Инструменты, такие как Dependency Walker, способны отображать как украшенные, так и невыделенные имена.

Неофициальная документации можно найти здесь: Name Decoration

Смежные вопросы