Вопрос или проблема
На UNIX я могу использовать команду вроде:
cc -o исполняемый_файл *.o -zlazyload -lsomelib
в результате чего библиотеки, перечисленные справа от -zlazyload
, помечаются тегом LAZYLOAD ELF в двоичном файле. Это можно проверить, вызвав dump -Lv исполняемый_файл
, и результат будет содержать, например:
**** ИНФОРМАЦИЯ О ДИНАМИЧЕСКОМ СЕКТОРЕ ****
.dynamic:
[ИНДЕКС] Тег Значение
[1] POSFLAG_1 LAZYLOAD
[2] NEEDED libsecdb.so.1
В этом случае libsecdb
не загружается во время запуска исполняемого файла, а откладывается до момента, когда вызывается первая функция из libsecdb
.
Этот трюк может быть использован для уменьшения представления исполняемого файла в памяти, если он не использует все возможности.
Существует ли способ добиться того же на Linux? Похоже, что GNU линковщик имеет флаг -zlazy
, но по моему опыту, это не дает эффекта.
Предпосылкой для этого вопроса является то, что на Solaris просто связать текущую оболочку Bourne (bosh), используя ленивую компоновку, и это приводит к оболочке, которая почти так же мала, как dash
при выполнении оболочных скриптов, но всё же быстрее, чем dash
. Общие библиотеки для интерактивного редактора истории связываются только в том случае, если оболочка используется в интерактивном режиме.
Я могу ошибаться, но думаю, что есть две вещи.
- загрузка (то есть, mmap’инг общей библиотеки в память) и
- связывание (то есть, разрешение символов)
На Linux -zlazy
включает ленивое связывание (и это значение по умолчанию, поэтому добавление его ничего не меняет). Я не знаю о какой-либо ленивой загрузке на Linux.
Ответ или решение
На вопрос о возможностях ленивой динамической линковки в Linux можно ответить достаточно подробно, учитывая различные аспекты работы с динамическими библиотеками и особенностями поведения систем UNIX и Linux.
Понимание ленивой динамической линковки
Ленивая динамическая линковка (lazy dynamic linking) — это механизм, при котором динамические библиотеки не загружаются в память до тех пор, пока не будет выполнен их первый вызов. Это позволяет снизить начальные затраты на загрузку программы и уменьшить занимаемую память, если не все функции библиотек используются.
Различия между UNIX и Linux
На платформе UNIX, например, в Solaris, действительно можно использовать опцию -zlazyload
, чтобы отложить загрузку библиотек до момента, когда они понадобятся. При этом, как вы правильно упомянули, в скомпилированном бинарном файле устанавливается специальный тег LAZYLOAD
в разделе динамики ELF.
Тем не менее, в мире Linux подобная функциональность не доступна в том виде, в котором она реализована в Solaris. Хотя linker GNU действительно предлагает флаг -zlazy
, он касается только ленивой привязки (lazy binding), а не ленивой загрузки (lazy loading).
Ленивая привязка и ее наличность
Ленивая привязка в Linux является стандартным поведением динамических библиотек. Это означает, что название флагов -zlazy
и соответствующие настройки компоновщика на самом деле могут не иметь эффекта, так как ленивую привязку Linux уже выполняет по умолчанию. То есть, если динамическая библиотека не используется, ее символы не будут разрешены до первого обращения к ним.
Ленивая загрузка
Однако, что касается ленивой загрузки библиотек, такой функциональности в Linux нет. Как уже было сказано, при запуске программы все динамические библиотеки, указанные в разделе NEEDED
, будут загружены, но не обязательно их символы будут разрешены до момента использования.
Альтернативные подходы
Если задача состоит в том, чтобы добиться эффектов, схожих с ленивой загрузкой, вы можете рассмотреть следующие стратегии:
-
Использование
dlfcn.h
: Этот заголовочный файл предоставляет функции для динамического связывания библиотек во время выполнения. С его помощью вы можете загружать библиотеки и вызывать функции по мере необходимости. Это требует дополнительных усилий по управлению временем загрузки и символами. -
Оптимизация кода: Если приток памяти является критическим фактором, вы можете попытаться оптимизировать код и избавиться от неиспользуемых функций или библиотек.
-
Создание разных версий исполняемого файла: Если часть функциональности необходима только в определённых ситуациях (например, интерактивный режим), можно создать отдельные исполняемые файлы для различных сценариев использования.
Заключение
Таким образом, в Linux невозможно реализовать ленивую динамическую линковку так, как это доступно в Solaris. Однако возможны другие подходы, которые могут помочь в уменьшении нагрузки на память и оптимизации. Если вы разрабатываете проекты, которые могут требовать подобной функциональности, обязательно рассматривайте доступные вам инструменты и библиотеки, повышающие гибкость архитектуры ваших приложений.