Как работает библиотека импорта? Подробности? - PullRequest
73 голосов
/ 26 августа 2010

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

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

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

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

Но иногда есть некоторые файлы LIB , поставляемые с файлами DLL, поэтому:

  • Для чего нужны эти файлы LIB?
  • Как они достигают того, для чего предназначены?
  • Существуют ли какие-либо инструменты, которые могут позволить мне проверить внутренности этих файлов LIB?

Обновление 1

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

Обновление 2

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

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

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

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

Я прав в этом? Есть что-то еще?

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

Ответы [ 4 ]

86 голосов
/ 26 августа 2010

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

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

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

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

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

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

Обновление

Если вы просто не можете устоять, зная, где все гайки иБолты действительно есть, и что действительно происходит, в MSDN всегда есть что-то, чтобы помочь.Статья Мэтта Пьетрека Углубленный взгляд на формат исполняемого файла Win32 представляет собой очень полный обзор формата файла EXE и его загрузки и запуска.Его даже обновили, чтобы он охватывал .NET и даже больше, так как он первоначально появился в журнале MSDN ca.2002.

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

Обновление 2

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

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

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

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

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

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

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

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

3 голосов
/ 23 января 2016

Эти файлы библиотеки импорта .LIB используются в следующем свойстве проекта, Linker->Input->Additional Dependencies, при создании группы библиотек DLL, которым требуется дополнительная информация во время компоновки, которая предоставляется файлами библиотеки импорта .LIB.В приведенном ниже примере, чтобы не получать ошибок компоновщика, мне нужно сослаться на DLL, A, B, C и D через их файлы lib.(обратите внимание, что компоновщику для поиска этих файлов может потребоваться указать путь их развертывания в Linker->General->Additional Library Directories, иначе вы получите ошибку сборки из-за невозможности найти какой-либо из предоставленных файлов lib.)

imageInput->Additional Dependencies">

Если ваше решение строит все динамические библиотеки, вы, возможно, смогли избежать этой явной спецификации зависимости, полагаясь вместо этого на флаги ссылок, отображаемые в диалоговом окне Common Properties->Framework and References.Эти флаги, по-видимому, автоматически выполняют связывание от вашего имени с использованием файлов * .lib.Framework and References

Однако, как говорится, Общие Свойства, которые не зависят от конфигурации или платформы.Если вам требуется поддержка смешанного сценария сборки, как в нашем приложении, у нас была конфигурация сборки для визуализации статической сборки и специальная конфигурация, которая создавала ограниченную сборку подмножества сборок, которые были развернуты как динамические библиотеки.Я использовал флаги Use Library Dependency Inputs и Link Library Dependencies, установленные в true в различных случаях, чтобы заставить вещи строить, а потом реализовать для упрощения вещей, но когда я представлял свой код для статических сборок, я ввел массу предупреждений компоновщика, и сборка была невероятноймедленно для статических сборок.В итоге я представил кучу предупреждений такого рода ...

warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored  D.lib(JSource.obj)

И я использовал ручную спецификацию Additional Dependencies, чтобы удовлетворить компоновщик динамических сборок, в то же время поддерживая статических сборщиков счастливыми.не используя общее свойство, которое замедлило их.При развертывании динамической сборки подмножества я развертываю только файлы dll, поскольку эти файлы lib используются только во время соединения, а не во время выполнения.

2 голосов
/ 26 августа 2010

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

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

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

0 голосов
/ 26 августа 2010
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...