Если функция объявлена со спецификатором
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, то компилятор распознает эту операцию и преобразует её в загрузку адреса из таблицы адресов импортируемых функций.
В результате этого дополнительного знания, сообщаемого компилятору, функции-заглушки больше не нужны; компилятор знает, что ему надо идти прямо к таблице адресов импортированных функций.
Неточность: "function in question is an imported function rather than a normal function with external linkage" - "рассматриваемая функция - это импортируемая функция, а не обычная функция с внешним связыванием". Речь идёт о функциях, расположенных в другом модуле, а не в этом же - для функций в этом же модуле экспортируемость не требуется.
ОтветитьУдалитьСпасибо за замечание - поправил.
ОтветитьУдалитьЯ имел в виду "исполняемый модуль", а не модуль в смысле unit. Мне почему-то показалось, что "функция с внешним связыванием" может быть не совсем понятным.