Как работает библиотека импорта? Подробности?

Я знаю, что это может показаться довольно простым для гиков. Но я хочу, чтобы это было предельно ясно.

Когда я хочу использовать Win32 DLL, обычно я просто вызываю API, такие как LoadLibrary () и GetProcAdderss (). Но в последнее время я занимаюсь разработкой с DirectX9, и мне нужно добавить файлы d3d9.lib , d3dx9.lib и т. Д.

Я слышал достаточно, что LIB предназначен для статической связи и DLL для динамического связывания.

Таким образом, в настоящее время я понимаю, что LIB содержит реализацию методов и статически связан во время соединения как часть окончательного EXE-файла. Хотя DLL динамически загружается во время выполнения и не является частью окончательного EXE-файла.

Но иногда существуют некоторые LIB-файлы , поставляемые с DLL-файлами, поэтому: Но мне интересно, как это работает с моим основным приложением и динамически загружаемыми DLL.

Обновление 2

Как сказал RBerteig, в файлах LIB есть некоторый код заглушки, созданный с помощью DLL. Таким образом, вызывающая последовательность должна быть такой:

Мое основное приложение -> заглушка в LIB -> настоящая целевая DLL

Итак, какая информация должна содержаться в этих LIB? Я мог бы подумать о следующем:

  • Файл LIB должен содержать полный путь соответствующей DLL; Таким образом, DLL может быть загружена во время выполнения.
  • Относительный адрес (или смещение файла?) Каждой точки входа каждого метода экспорта DLL должен быть закодирован в заглушке; Так что правильные переходы / вызовы методов могут быть сделаны.

Прав ли я в этом? Есть ли что-то еще?

Кстати: есть ли инструмент, который может проверять библиотеку импорта? Если я это увижу, сомнений больше не будет.

76
задан jxramos 22 January 2016 в 23:14
поделиться

3 ответа

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

При явном использовании во время выполнения вы используете LoadLibrary() и GetProcAddress(), чтобы вручную загрузить DLL и получить указатели на функции, которые необходимо вызвать.

При неявной компоновке при сборке программы заглушки для каждого экспорта DLL, используемого программой, связываются с программой из библиотеки импорта, и эти заглушки обновляются по мере загрузки EXE и DLL при запуске процесса. . (Да, здесь я несколько упростил...)

Эти заглушки должны откуда-то браться, а в цепочке инструментов Microsoft они берутся из особой формы файла .LIB, называемой библиотекой импорта. . Требуемый .LIB обычно создается одновременно с DLL и содержит заглушку для каждой функции, экспортируемой из DLL.

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

Между прочим, если вы используете набор инструментов GCC, вам фактически не нужны библиотеки импорта для соответствия вашим библиотекам DLL. Версия компоновщика Gnu, перенесенная на Windows, понимает библиотеки DLL напрямую и может синтезировать большинство необходимых заглушек на лету.

Обновление

Если вы просто не можете удержаться от того, чтобы не узнать, где на самом деле все гайки и болты и что происходит на самом деле, на MSDN всегда есть чем помочь. Статья Мэтта Питрека An In-Depth Look in the Win32 Portable Executable File Format представляет собой очень полный обзор формата EXE-файла и того, как он загружается и запускается. Он даже был обновлен, чтобы охватывать .NET и многое другое, поскольку он первоначально появился в журнале MSDN Magazine ок. 2002.

Кроме того, может быть полезно знать, как узнать, какие именно библиотеки DLL используются программой. Инструментом для этого является Dependency Walker, также известный как depend.exe. Его версия включена в Visual Studio, но последнюю версию можно получить у автора по адресу http://www.dependencywalker.com/. Он может идентифицировать все библиотеки DLL, указанные во время компоновки (как с ранней загрузкой, так и с отложенной загрузкой), а также может запускать программу и отслеживать любые дополнительные библиотеки DLL, которые она загружает во время выполнения.

Обновление 2.

Я переформулировал часть предыдущего текста, чтобы уточнить его при повторном прочтении и использовать термины искусства неявные и явные ссылки для единообразия. с MSDN.

Итак, у нас есть три способа сделать библиотечные функции доступными для использования программой. Очевидный последующий вопрос звучит так: «Как мне выбрать, какой путь?»

Статическое связывание — это то, как связывается большая часть самой программы. Все ваши объектные файлы перечислены и собраны компоновщиком в EXE-файл. Попутно компоновщик берет на себя мелкие хлопоты, такие как исправление ссылок на глобальные символы, чтобы ваши модули могли вызывать функции друг друга. Библиотеки также могут быть статически связаны. Объектные файлы, составляющие библиотеку, собираются библиотекарем в файле .LIB, в котором компоновщик ищет модули, содержащие необходимые символы. Одним из эффектов статической компоновки является то, что с ней компонуются только те модули из библиотеки, которые используются программой; другие модули игнорируются. Например, традиционная математическая библиотека C включает множество функций тригонометрии. Но если вы свяжетесь с ним и используете cos(), вы не получите копию кода для sin() или tan() если вы также не вызвали эти функции. Для больших библиотек с богатым набором функций такое выборочное включение модулей важно. На многих платформах, таких как встроенные системы, общий размер кода, доступного для использования в библиотеке, может быть большим по сравнению с пространством, доступным для хранения исполняемого файла на устройстве. Без выборочного включения было бы сложнее управлять деталями создания программ для этих платформ.

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

DLL для библиотеки содержит все ее функции, готовые к использованию любой клиентской программой. Если многие программы загружают эту DLL, все они могут совместно использовать ее кодовые страницы. Все выигрывают. (Ну, до тех пор, пока вы не обновите DLL новой версией, но это не является частью этой истории. Google DLL — к черту эту сторону истории.)

Итак, первый большой выбор, который нужно сделать при планировании нового проекта, — это между динамическая и статическая связь. При статической компоновке вам нужно установить меньше файлов, и вы защищены от третьих лиц, обновляющих используемую вами DLL. Однако ваша программа больше, и она не так хороша для экосистемы Windows. С динамической компоновкой вам нужно установить больше файлов, у вас могут возникнуть проблемы с обновлением третьей стороной используемой вами библиотеки DLL, но вы, как правило, более дружелюбны к другим процессам в системе.

Большим преимуществом DLL является то, что ее можно загружать и использовать без перекомпиляции или даже повторной компоновки основной программы. Это может позволить стороннему поставщику библиотек (например, Microsoft и среда выполнения C) исправить ошибку в своей библиотеке и распространить ее.Как только конечный пользователь установит обновленную библиотеку DLL, он сразу же получит преимущество исправления ошибки во всех программах, использующих эту библиотеку DLL. (Если только это ничего не ломает. См. DLL Hell.)

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

90
ответ дан 24 November 2019 в 11:22
поделиться

Существует три типа библиотек: статические, совместно используемые и динамически загружаемые библиотеки.

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

Динамически загружаемые библиотеки очень похожи на разделяемые библиотеки, за исключением того, что они загружаются, когда и если возникает необходимость в написанном вами коде.

2
ответ дан 24 November 2019 в 11:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: