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



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



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



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



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



но иногда, есть некоторые LIB файлы иду с файлы DLL, так что:




  • для чего нужны эти файлы LIB?

  • как они достигают того, для чего они предназначены?

  • есть ли какие-либо инструменты, которые могут позволить мне проверить внутренности эти файлы LIB?


обновление 1



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



обновление 2



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



моя главная программа --> заглушка в LIB -- > real target DLL



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




  • файл LIB должен содержать полный путь к соответствующей DLL; поэтому DLL может быть загружен во время выполнения.

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


Я прав в этом? Быть там что-то еще?



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

1055   4  

4 ответов:

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

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

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

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

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

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

обновление

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

кроме того, может быть полезно знать, как точно узнать, какие библиотеки DLL используются программой. Инструмент для этого-Dependency Walker, он же depends.исполняемый. Его версия входит в состав 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, возможно, даже не существовало, когда программа была написана и опубликована. Это позволяет использовать механизмы расширения, которые могут обнаруживать и загружать плагины, например.

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

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

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

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

Linker->Input->Additional Dependencies

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

это, однако, как он говорит a Common свойства, которые не зависит от конфигурации или платформы. Если вам нужно поддерживать смешанный сценарий сборки, как в нашем приложении, у нас была конфигурация сборки для визуализации статической сборки и специальная конфигурация, которая построила ограниченную сборку подмножества сборок, которые были развернуты как динамические библиотеки. Я использовал 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 используются только во время ссылки, а не во время выполнения.

Comments

    Ничего не найдено.