среда, 31 августа 2011 г.

Как экспортируются DLL функции в 32-битных Windows?

Это перевод How are DLL functions exported in 32-bit Windows? Автор: Реймонд Чен.

Дизайнерам 32-битных Windows не нужно было беспокоиться о втискивании в 256 Кб памяти. Поскольку модули в Win32 построены на загрузке по запросу, то всё, что вам нужно сделать - спроецировать весь образ в память, а затем коснуться тех частей, которые вам нужны. Поэтому нет никакого различия между резидентной и не резидентной таблицами, так что имена экспортируемых функций просто записываются в исполняемый образ вместе с указателем (вернее относительным виртуальным адресом) на имя, хранимое в таблице экспорта.

В отличие от главной 16-битной таблицы экспорта, 32-битная таблица не является разрежённой. Иными словами, если ваша DLL экспортирует две функции с номерами 10 и 1000 - у вас будет таблица экспорта на 991 записей, состоящая из двух функций и кучи нулей. Поэтому вам не следует назначать номера функциям с большими пробелами в нумерации - иначе вы будете зря тратить пространство в таблице экспорта.

Как я заметил выше, теперь есть только одна таблица экспортируемых имён, поскольку вам не нужно делать отличия между резидентными и не резидентными именами. Таблица экспортируемых имён работает в той же манере, что и в 16-битных Windows, проецируя имена на номера. В отличие от 16-битных таблиц, где порядок не имеет значения, таблица экспортируемых имён в 32-битных Windows должна быть отсортирована, чтобы система могла воспользоваться (эффективным) двоичным поиском для ускорения поиска имён.

Как и в 16-битных Windows, каждому имени присваивается номер. Если программист не указывает номер, то его назначает компоновщик, и, как и в 16-битных Windows, автоматически присваиваемые значения могут отличаться в сборках. Однако тут есть существенное отличие в моделях использования: вспомните, что в 16-битных Windows импорт по имени не поощрялся (по соображениям производительности), и в результате обычно каждой экспортируемой функции явно присваивался номер, что и было предпочтительным способом связывания функций. С другой стороны, именованный импорт в Win32 является нормой, а явное присваивание номеров функций ушло в прошлое. Это означает, что номера в таблице экспорта не фиксированы. К примеру, посмотрите на номера, присваиваемые функции LocalAlloc из kernel32 за эти годы:

Windows NT 3.1314
Windows NT 3.5372
Windows 95501
Windows NT 4.0407

Но некоторые люди имеют привычку "взламывать" (reverse-engineer) библиотеки импорта - вероятно потому, что им лень качать Platform SDK чтобы получить официальные библиотеки импорта. Проблема с генерацией библиотеки импорта заключается в том, что вы не можете сказать, был ли номер, скажем, функции LoadLibrary присвоен явно программистом (и, значит, будет постоянен) или же был назначен автоматически компоновщиком (и в этом случае он будет меняться). Утилиты генерации библиотек импорта могут просто перестраховаться и всегда использовать именованный импорт, но по какой-то причине они часто предпочитают импорт по номерам (вероятно, это остаток из времён 16-битных Windows, где такой способ импорта был предпочитаемым).

Этот неудачный выбор части утилит по генерации библиотек импорта жить опасной жизнью создал проблемы совместимости команде DirectX (я не знаю, почему именно DirectX оказался под ударом больше остальных. Возможно, потому что у разработчиков игр нет времени учить детали Win32; они просто хотят писать их игры). Как только кто-то использовал такую утилиту, он оказался привязанным к функциям DirectX вроде DirectDrawCreate по номеру, а не по имени. А когда вышла следующая версия DirectX и этому имени был присвоен другой номер компоновщиком, их программы стали вылетать. Команде DirectX пришлось поднять из архива старые DLL, тщательно выписать все номера функций (присвоенные случайным образом компоновщиком) и в точности повторить это присвоение вручную, так чтобы эти номера более не менялись бы в будущем.

Есть и другие причины, почему вы не можете сгенерировать библиотеку импорта по DLL; я подниму эти причины в следующий раз, когда буду обсуждать импорт из DLL.

В следующий раз - переходники.

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.