воскресенье, 4 сентября 2011 г.

Как менее наивный компилятор вызывает импортируемую функцию

Это перевод How a less naive compiler calls an imported function. Автор: Реймонд Чен.

Если функция объявлена со спецификатором dllimport, то это указывает компилятору Visual Studio C/C++, что эта функция импортируется из другого (исполняемого) модуля, а не является обычной функцией в этом же исполняемом модуле. Имея на руках эту информацию, компилятор генерирует немного другой код, поскольку теперь он осведомлён об особенностях импортируемых функций.

Во-первых, теперь больше нет необходимости в функции-заглушке, потому что компилятор может сгенерировать инструкцию call [__imp__FunctionName]. Кроме того, компилятор знает, что этот адрес (адрес импортируемой функции) никогда не меняется, и, соответственно, он может оптимизировать многократное использование этого адреса, например:
    mov   ebx, [__imp__FunctionName]
    push  1
    call  ebx ; FunctionName(1)
    push  2
    call  ebx ; FunctionName(2)
(Примечание к сумасшедшим людям: подобная оптимизация означает, что у вас могут возникнуть проблемы, если вы исправляете таблицу импорта модуля после того, как код в модуле начал работу - потому что указатель на функцию может быть сохранён в регистр до того, как вы начали править импорт. Рассмотрите случай с примером выше, когда вы изменили запись в таблице __imp__FunctionName после выполнения инструкции mov ebx, [__imp__FunctionName]: ваша функция-перехватчик не будет вызвана, потому что старый указатель на функцию сохранён в регистре ebx).

Аналогично, если ваша программа попытается взять адрес импортируемой функции, которая была объявлена со спецификатором dllimport, то компилятор распознает эту операцию и преобразует её в загрузку адреса из таблицы адресов импортируемых функций.

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

2 комментария:

  1. Неточность: "function in question is an imported function rather than a normal function with external linkage" - "рассматриваемая функция - это импортируемая функция, а не обычная функция с внешним связыванием". Речь идёт о функциях, расположенных в другом модуле, а не в этом же - для функций в этом же модуле экспортируемость не требуется.

    ОтветитьУдалить
  2. Спасибо за замечание - поправил.

    Я имел в виду "исполняемый модуль", а не модуль в смысле unit. Мне почему-то показалось, что "функция с внешним связыванием" может быть не совсем понятным.

    ОтветитьУдалить

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

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

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

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

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