Общая библиотека или общий объект — это компьютерный файл , содержащий исполняемый код , предназначенный для использования несколькими компьютерными программами или другими библиотеками во время выполнения .
При запуске программы, настроенной на использование общей библиотеки, операционная система загружает общую библиотеку из файла (отличного от исполняемого файла программы) в память во время загрузки или выполнения . Для перспективы, программа может быть альтернативно монолитной — построенной так, чтобы включать исполняемый код библиотеки в свой исполняемый файл, но код библиотеки, встроенный в исполняемый файл программы, не может использоваться другими программами.
Общие библиотеки могут быть статически скомпонованы во время компиляции, что означает, что ссылки на библиотеку разрешаются, и библиотеке выделяется память при создании исполняемого файла. [ необходима цитата ] Но часто линковка общих библиотек откладывается до тех пор, пока они не будут загружены. [ сомнительно – обсудить ]
Большинство современных операционных систем используют один и тот же формат как для общих библиотек, так и для исполняемых файлов. [NB 1] Это дает два основных преимущества: во-первых, требуется только один загрузчик (создание и поддержка одного загрузчика считается оправданным любой дополнительной сложностью). [ требуется цитата ] Во-вторых, это позволяет использовать исполняемый файл как общую библиотеку (если у него есть таблица символов ). Примерами форматов файлов, используемых как для общих библиотек, так и для исполняемых файлов, являются ELF , Mach-O и PE .
В некоторых старых средах, таких как 16-разрядная Windows или MPE для HP 3000 , в коде общей библиотеки допускались только стековые данные (локальные) или на код общей библиотеки накладывались другие существенные ограничения.
Библиотечный код может совместно использоваться в памяти несколькими процессами и на диске. Если используется виртуальная память, процессы будут выполнять одну и ту же физическую страницу ОЗУ, которая отображается в различные адресные пространства процессов. Это имеет преимущества. Например, в системе OpenStep приложения часто имели размер всего несколько сотен килобайт и загружались быстро; большая часть их кода находилась в библиотеках, которые уже были загружены для других целей операционной системой. [ необходима цитата ]
Программы могут выполнять совместное использование ОЗУ, используя позиционно-независимый код , как в Unix , что приводит к сложной, но гибкой архитектуре, или используя общие виртуальные адреса, как в Windows и OS/2 . Эти системы гарантируют, различными способами, такими как предварительное отображение адресного пространства и резервирование слотов для каждой общей библиотеки, что код имеет высокую вероятность совместного использования. Третьей альтернативой является одноуровневое хранилище , используемое IBM System/38 и его преемниками. Это допускает позиционно-зависимый код, но не накладывает существенных ограничений на то, где может быть размещен код или как он может быть совместно использован.
В некоторых случаях разные версии общих библиотек могут вызывать проблемы, особенно когда библиотеки разных версий имеют одинаковое имя файла, а разные приложения, установленные в системе, требуют определенную версию. Такой сценарий известен как DLL hell , названный в честь файла DLL Windows и OS/2 . Большинство современных операционных систем после 2001 года имеют методы очистки для устранения таких ситуаций или используют «частные» библиотеки, специфичные для приложений. [1]
Динамическое связывание или позднее связывание — это связывание, выполняемое во время загрузки программы ( время загрузки ) или ее выполнения ( время выполнения ), а не во время создания исполняемого файла. Динамически подключаемая библиотека ( динамически подключаемая библиотека или DLL в Windows и OS/2 ; общий образ в OpenVMS ; [2] динамический общий объект или DSO в Unix-подобных системах) — это библиотека, предназначенная для динамического связывания. При создании исполняемого файла компоновщик выполняет лишь минимальный объем работы ; он только записывает, какие библиотечные процедуры нужны программе, а также имена индексов или номера процедур в библиотеке. Большая часть работы по связыванию выполняется во время загрузки приложения (время загрузки) или во время выполнения (время выполнения). Обычно необходимая программа связывания, называемая динамическим компоновщиком или загрузчиком связывания , фактически является частью базовой операционной системы . (Однако возможно, и не слишком сложно, написать программу, которая использует динамическое связывание и включает в себя собственный динамический компоновщик, даже для операционной системы, которая сама по себе не поддерживает динамическое связывание.)
Первоначально программисты разработали динамическое связывание в операционной системе Multics , начиная с 1964 года, и MTS ( Michigan Terminal System ), созданной в конце 1960-х годов. [3]
Поскольку общие библиотеки в большинстве систем не меняются часто, системы могут вычислять вероятный адрес загрузки для каждой общей библиотеки в системе до того, как она понадобится, и сохранять эту информацию в библиотеках и исполняемых файлах. Если каждая загружаемая общая библиотека прошла этот процесс, то каждая будет загружаться по своему предопределенному адресу, что ускоряет процесс динамического связывания. Эта оптимизация известна как предварительное связывание или предварительное связывание в macOS и Linux соответственно. IBM z/VM использует похожую технику, называемую «Discontinuous Saved Segments» (DCSS). [4] Недостатки этой техники включают время, необходимое для предварительного вычисления этих адресов каждый раз, когда общие библиотеки изменяются, невозможность использовать рандомизацию макета адресного пространства и требование достаточного виртуального адресного пространства для использования (проблема, которая будет смягчена принятием 64-битных архитектур, по крайней мере на данный момент).
Загрузчики для общих библиотек сильно различаются по функциональности. Некоторые зависят от исполняемого файла, хранящего явные пути к библиотекам. Любое изменение наименования библиотеки или структуры файловой системы приведет к сбою этих систем. Чаще всего в исполняемом файле хранится только имя библиотеки (а не путь), а операционная система предоставляет метод поиска библиотеки на диске на основе некоторого алгоритма.
Если общая библиотека, от которой зависит исполняемый файл, удалена, перемещена или переименована, или если несовместимая версия библиотеки скопирована в место, которое находится раньше в поиске, исполняемый файл не загрузится. Это называется адом зависимостей , существующим на многих платформах. (Печально известный) вариант Windows обычно известен как ад DLL . Эта проблема не может возникнуть, если каждая версия каждой библиотеки уникально идентифицирована и каждая программа ссылается на библиотеки только по их полным уникальным идентификаторам. Проблемы «ада DLL» в более ранних версиях Windows возникли из-за использования только имен библиотек, которые не были гарантированно уникальными, для разрешения динамических ссылок в программах. (Чтобы избежать «ада DLL», более поздние версии Windows в значительной степени полагаются на опции программ для установки частных DLL — по сути, частичное отступление от использования общих библиотек — наряду с механизмами для предотвращения замены общих системных DLL более ранними их версиями.)
Microsoft Windows проверяет реестр , чтобы определить правильное место для загрузки DLL, которые реализуют объекты COM , но для других DLL он будет проверять каталоги в определенном порядке. Сначала Windows проверяет каталог, в который она загрузила программу ( private DLL [1] ); любые каталоги, заданные вызовом SetDllDirectory()
функции; каталоги System32, System и Windows; затем текущий рабочий каталог; и, наконец, каталоги, указанные переменной среды PATH . [5] Приложения, написанные для .NET Framework (с 2002 года), также проверяют глобальный кэш сборок как основное хранилище общих файлов DLL, чтобы устранить проблему DLL hell .
OpenStep использовал более гибкую систему, собирая список библиотек из ряда известных расположений (по аналогии с концепцией PATH) при первом запуске системы. Перемещение библиотек не вызывает никаких проблем, хотя пользователи несут временные затраты при первом запуске системы.
Большинство Unix-подобных систем имеют «путь поиска», указывающий каталоги файловой системы , в которых следует искать динамические библиотеки. Некоторые системы указывают путь по умолчанию в файле конфигурации , другие жестко кодируют его в динамическом загрузчике. Некоторые форматы исполняемых файлов могут указывать дополнительные каталоги, в которых следует искать библиотеки для определенной программы. Обычно это можно переопределить с помощью переменной среды , хотя она отключена для программ setuid и setgid, так что пользователь не может заставить такую программу запустить произвольный код с правами root. Разработчикам библиотек рекомендуется размещать свои динамические библиотеки в местах в пути поиска по умолчанию. С другой стороны, это может сделать установку новых библиотек проблематичной, и эти «известные» местоположения быстро становятся домом для все большего числа файлов библиотек, что усложняет управление.
Динамическая загрузка, подмножество динамического связывания, включает в себя динамически связанную библиотеку, загружаемую и выгружаемую во время выполнения по запросу. Такой запрос может быть сделан неявно или явно. Неявные запросы делаются, когда компилятор или статический компоновщик добавляет ссылки на библиотеки, которые включают пути к файлам или просто имена файлов. [ необходима цитата ] Явные запросы делаются, когда приложения делают прямые вызовы API операционной системы.
Большинство операционных систем, поддерживающих динамически подключаемые библиотеки , также поддерживают динамическую загрузку таких библиотек через API компоновщика времени выполнения . Например, Microsoft Windows использует функции API , и с библиотеками Microsoft Dynamic Link ; системы на базе POSIX , включая большинство UNIX и UNIX-подобных систем, используют , и . Некоторые системы разработки автоматизируют этот процесс.LoadLibrary
LoadLibraryEx
FreeLibrary
GetProcAddress
dlopen
dlclose
dlsym
Частные DLL — это DLL, которые устанавливаются вместе с определенным приложением и используются только этим приложением.