Есть причина, почему декорированы имена в библиотеке импорта.


Перевод с блога The Old New Thing. Оригинал здесь.

Когда я писал, что символические имена в таблице импортируемых функций имеют вид __imp__FunctionName, это было не совсем верно. В реальности все немного запутаннее и причина путаницы – декорирование имен функций.

Когда наивный компилятор генерирует ссылку на функцию, эта ссылка декорируется в соответствии с архитектурой, языком программирования и соглашением о вызове. Например, в результате "наивного" вызова функции GetVersion будет сгенерирован код, эквивалентный call _GetVersion@0 (для архитектуры х86, на других архитектурах декорирование отличается). Следовательно, библиотека импорта должна содержать символ _GetVersion@0, для того, чтобы соответствовать внешней ссылке.

Соответствием функции-заглушке, чье фактическое имя _GetVersion@0, является запись в таблице импорта с именем __imp__GetVersion@0. Вообще, имя в таблице импорта – это декорированное имя функции с префиксом __imp_.

Тот факт, что имена в библиотеках импорта декорированы, является еще одним важным поводом использовать официальную библиотеку импорта для необходимой вам DLL, вместо того, чтобы пытаться сделать ее самому при помощи каких-то программ. Как мы видели ранее, такие программы не будут знать, был ли номер, соответствующий некоторой функции, назначен преднамеренно или случайным образом. Но более того, программа не будет знать, какое декорирование необходимо применить для функции (если функция было экспортирована под недекорированным именем.) Следовательно, ваши попытки вызвать функцию вызовут ошибку на этапе линковки, так как декорированные имена скорее всего не  совпадут.

В этом отступлении я упомянул об экспортировании под недекорированным именем. Разве это не означает, что вы также можете экспортировать с декорированным именем? Да, можете, но как я объяснял ранее, этого не следует делать. Если вы экспортируете декорированное имя, то такое имя не может быть обнаружено при помощи GetProcAddress пока вы не передадите в GetProcAddress декорированное имя. Но способ декорирования меняется от языка к языку, от архитектуры к архитектуре, и даже от одного производителя компилятора к другому, так что даже если вы будете передавать декорированное имя в функцию GetProcAddress, вам придется заворачивать этот вызов в бесконечное множество #ifdef’ов для каждой платформы и для каждого компилятора. И горе вам, если вы надеетесь вызвать такую функцию из Visual Basic или C# или другого языка, который поддерживает interop.

Просто экспортируйте имена недекорированными. Ваши будущие клиенты скажут вам спасибо.

Реклама
Запись опубликована в рубрике DLL. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s