Когда ваш исходный код статически вызывает экспортированные функции DLL, или статически обращается к экспортированным переменным DLL, эти ссылки компилируются в промежуточные объектные файлы исполняемого файла в виде указателей, значения которых заполняются в время выполнения.
Когда компоновщик объединяет сгенерированные компилятором объектные файлы, чтобы сделать конечный исполняемый файл, он должен выяснить, на что фактически ссылаются все сгенерированные компилятором ссылки. Если он не может сопоставить данную ссылку с каким-либо фрагментом кода в вашем исполняемом файле, ему нужно вместо этого сопоставить его с внешней DLL. Поэтому необходимо знать, на какие библиотеки даже смотреть, и как эти библиотеки экспортируют вещи. DLL может экспортировать данную функцию / переменную по имени ИЛИ по порядковому номеру, поэтому компоновщику нужен способ сопоставить идентификаторы, используемые ссылками вашего кода, с конкретными записями в таблицах EXPORTS
конкретных файлов .dll
(особенно в случай, когда вещи экспортируются по порядковым номерам). Файлы Static-link .lib
предоставляют компоновщику эту информацию о сопоставлении (т. Е. FunctionA
сопоставляется с Ordinal 123
в DLL XYZ.dll
, FunctionB
сопоставляется с именем _FunctionB@4
в DLL ABC.dll
и т. Д.).
Затем компоновщик может заполнить таблицу IMPORTS
вашего исполняемого файла информацией о соответствующих необходимых EXPORTS
записях, а затем заставить ссылки DLL в вашем коде указывать на правильные IMPORTS
записи (если компоновщик может ' Чтобы разрешить сгенерированную компилятором ссылку на фрагмент кода в вашем исполняемом файле или на определенный экспорт DLL, он прерывается с «неразрешенной внешней» ошибкой).
Затем, когда ваш исполняемый файл загружается во время выполнения, загрузчик ОС просматривает таблицу IMPORTS
, чтобы узнать, какие экспорты DLL необходимы, поэтому он может затем загрузить соответствующие DLL в память и обновить записи в * Таблица 1024 * с реальными адресами памяти, основанными на таблице EXPORTS
каждой библиотеки DLL (если не удается загрузить указанную DLL-библиотеку или не удается найти ссылочный экспорт, загрузчик ОС прерывает загрузку исполняемого файла). Таким образом, когда ваш код вызывает функции DLL или обращается к переменным DLL, эти обращения идут в правильные места.
Все изменится, если ваш исходный код динамически обращается к функциям / переменным DLL через явные вызовы GetProcAddress()
во время выполнения. В этом случае файлы static-link .lib
не требуются для такого доступа, поскольку ваш собственный код обрабатывает загрузку DLL в память и находит экспорт, который он хочет использовать.
Тем не менее, существует третий вариант, который объединяет вышеупомянутые сценарии: вы можете написать свой код для доступа к функциям / переменным DLL статически , но использовать функцию компоновщика delay-load (если он есть). В этом случае вам по-прежнему нужны файлы static-link .lib
для каждой загруженной с задержкой DLL, к которой вы обращаетесь, но компоновщик заполняет отдельную таблицу DELAYLOAD
в вашем исполняемом файле ссылками на экспорт DLL вместо заполнения IMPORTS
Таблица. Он указывает сгенерированные компилятором ссылки DLL на заглушки в RTL вашего компилятора, которые заменят ссылки на адреса из GetProcAddress()
при первом обращении к заглушкам во время выполнения, что исключает необходимость заполнения ссылок загрузчик ОС во время загрузки. Это позволяет вашему исполняемому файлу нормально работать, даже если экспорт DLL отсутствует во время загрузки, и, возможно, даже не нужно загружать библиотеки DLL вообще, если они никогда не используются (конечно, если ваш исполняемый файл пытается получить доступ к экспорту DLL) динамически, и он не загружается, ваш код, скорее всего, потерпит крах, но это отдельная проблема).