KasperskyOS Community Edition 1.3
Содержание
Использование динамических библиотек
В решении на базе KasperskyOS можно использовать динамические библиотеки (файлы *.so
). По сравнению со статическими библиотеками (файлами *.a
) динамические библиотеки дают следующие преимущества:
- Экономия оперативной памяти.
Несколько процессов могут использовать один экземпляр динамической библиотеки. Также исполняемый файл и динамические библиотеки в одном процессе могут использовать один экземпляр динамической библиотеки.
Динамические библиотеки могут загружаться в память и выгружаться из нее по инициативе программ, которые их используют.
- Удобство обновления ПО.
Обновление динамической библиотеки распространяется на все зависимые от нее исполняемые файлы и динамические библиотеки без их повторной сборки.
- Возможность реализовать механизм плагинов.
Плагины для компонентов решения представляют собой динамические библиотеки.
- Совместное использование кода и данных.
Один экземпляр динамической библиотеки может совместно использоваться несколькими процессами, а также исполняемым файлом и динамическими библиотеками в одном процессе. Это позволяет, например, централизованно управлять множественным доступом к ресурсам или хранить общие данные.
Динамические библиотеки поставляются в составе KasperskyOS Community Edition, а также могут быть созданы разработчиком решения на базе KasperskyOS. Работоспособность сторонних динамических библиотек не гарантируется.
В настоящее время из-за технических ограничений в решении на базе KasperskyOS нельзя использовать libc.so
и libpthread.so
.
Условия, необходимые для использования динамических библиотек
Чтобы использовать динамические библиотеки в решении на базе KasperskyOS, нужно выполнить следующие условия:
- Процессы, использующие динамические библиотеки, должны иметь доступ к файловым системам, в которых хранятся файлы динамических библиотек. Доступ к файловым системам обеспечивается VFS, которая является отдельным процессом. VFS и другое ПО, с помощью которого VFS работает с накопителем (например драйвер накопителя), не должны использовать динамические библиотеки.
- Системная программа
BlobContainer
должна быть включена в решение. - Исполняемые файлы, использующие динамические библиотеки, должны быть собраны с флагом
-rdynamic
(с динамической компоновкой).CMake
-командаinitialize_platform()
делает так, что для сборки всех исполняемых файлов, заданных черезCMake
-командыadd_executable()
, этот флаг используется автоматически.
Если CMake
-команда initialize_platform(FORCE_STATIC)
указана в корневом файле CMakeLists.txt
, то тулчейн выполняет статическую компоновку исполняемых файлов.
CMake
-команда project_static_executable_header_default()
влияет на сборку исполняемых файлов, заданных через последующие CMake
-команды add_executable()
в одном файле CMakeLists.txt
. Тулчейн выполняет статическую компоновку этих исполняемых файлов.
CMake
-команда platform_target_force_static()
влияет на сборку одного исполняемого файла, заданного через CMake
-команду add_executable()
. Тулчейн выполняет статическую компоновку этого исполняемого файла.
Исполняемый файл, который собирается с флагом -rdynamic
, компонуется со статической библиотекой, если динамическая библиотека не найдена. Например, если используется CMake
-команда target_link_libraries
(client -lm)
, исполняемый файл программы client
компонуется со статической библиотекой libm.a
, если динамическая библиотека libm.so
не найдена.
Жизненный цикл динамической библиотеки
Жизненный цикл динамической библиотеки включает следующие стадии:
- Загрузка в память.
Динамическая библиотека, скомпонованная с исполняемым файлом, загружается в разделяемую память при запуске процесса, созданного на основе этого исполняемого файла. Также процесс может загрузить динамическую библиотеку в разделяемую память вызовом функции
dlopen()
интерфейса POSIX. Динамическая библиотека может быть скомпонована с другими динамическими библиотеками, поэтому исполняемый файл зависит не только от непосредственно скомпонованной с ним динамической библиотеки, но и от всего графа зависимостей этой библиотеки. Динамическая библиотека загружается в разделяемую память совместно с всеми динамическими библиотеками, от которых зависит.Один экземпляр динамической библиотеки загружается в разделяемую память независимо от того, сколько процессов использует эту библиотеку. (Точнее, в разделяемую память загружается только часть динамической библиотеки, включающая код и доступные только на чтение данные. Другая часть динамической библиотеки загружается в память каждого процесса, который использует эту библиотеку.) Динамическая библиотека, от которой зависит нескольких других динамических библиотек, загружается в разделяемую память в единственном экземпляре.
Если задать через переменную окружения
LD_PRELOAD
список динамических библиотек, то эти динамические библиотеки будут загружены в разделяемую память, даже если исполняемый файл не зависит от них. (Элементами списка должны быть абсолютные или относительные пути к динамическим библиотекам, разделенные двоеточием, например:LD_PRELOAD=libmalloc.so:libfree.so:/usr/somepath/lib/libfoo.so
.) Функции, которые экспортируются динамическими библиотеками, указанными вLD_PRELOAD
, замещают одноименные функции, которые экспортируются другими динамическими библиотеками. Это можно использовать для целей отладки, если требуется подменить функции, импортируемые из динамических библиотек.Загрузчик динамических библиотек выполняет поиск динамических библиотек в следующем порядке:
- По абсолютным путям, заданным через переменную окружения
LD_LIBRARY_PATH
.Пути должны быть разделены двоеточием, например:
LD_LIBRARY_PATH=/usr/lib:/home/user/lib
. - По абсолютным путям, заданным в поле
DT_RUNPATH
илиDT_RPATH
секции.dynamic
исполняемых файлов и динамических библиотек.При компоновке исполняемых файлов и динамических библиотек могут быть заданы пути, по которым загрузчик динамических библиотек будет выполнять поиск. (Это можно сделать, например, через свойство
INSTALL_RPATH
вCMake
-командеset_target_properties()
.) Пути для поиска динамических библиотек сохраняются в полеDT_RUNPATH
илиDT_RPATH
секции.dynamic
. Это поле может быть как в исполняемых файлах, скомпонованных с динамическими библиотеки, так и в самих динамических библиотеках, скомпонованных с другими динамическими библиотеками. - По пути
/lib
.
Загрузчик динамических библиотек выполняет поиск в том же порядке, если в параметре
filename
функцииdlopen()
или в переменной окруженияLD_PRELOAD
указан относительный путь к динамической библиотеке. Если указан абсолютный путь, то загрузчик помещает динамическую библиотеку в разделяемую память без выполнения поиска. - По абсолютным путям, заданным через переменную окружения
- Использование процессом (процессами).
- Выгрузка из памяти.
Динамическая библиотека выгружается из разделяемой памяти, когда все процессы, использующие эту библиотеку, завершились или вызвали функцию
dlclose()
интерфейса POSIX. Динамическая библиотека, скомпонованная с исполняемым файлом, не может быть выгружена из разделяемой памяти до завершения процесса, который был создан на основе этого исполняемого файла. Динамическая библиотека, скомпонованная с другими динамическими библиотеками, выгружается из разделяемой памяти после выгрузки всех библиотек, которые зависят от нее.
Включение системной программы BlobContainer в решение на базе KasperskyOS
Если в решении используются динамические библиотеки, то в это решение должна быть включена системная программ BlobContainer
(исполняемый файл sysroot-aarch64-kos/bin/BlobContainer
из состава KasperskyOS Community Edition).
Программа BlobContainer
может быть включена в решение автоматически или вручную. Автоматическое включение этой программы в решение выполняется CMake
-командами build_kos_qemu_image()
и build_kos_hw_image()
, если как минимум один исполняемый файл в решении скомпонован с динамической библиотекой. (Чтобы отключить автоматическое включение программы BlobContainer
в решение, нужно добавить значение NO_AUTO_BLOB_CONTAINER
в параметры CMake
-команд build_kos_qemu_image()
и build_kos_hw_image()
.) Если программы в решении работают с динамическими библиотеками, используя только интерфейс POSIX (функции dlopen()
, dlsym()
, dlerror()
, dlclose()
), то программу BlobContainer
нужно включить в решение вручную.
VFS, работающая с файлами динамических библиотек, должна быть отдельным процессом. Нужно создать IPC-канал от процесса программы BlobContainer
к процессу VFS.
Должны быть созданы IPC-каналы от процессов, использующих динамические библиотеки, к процессу программы BlobContainer
. Эти IPC-каналы могут быть созданы как статически, так и динамически. Если статически созданный IPC-канал отсутствует, клиентская и серверная части программы BlobContainer
пытаются создать IPC-канал динамически, используя сервер имен.
Если программа BlobContainer
включена в решение автоматически, то макросы @INIT_EXTERNAL_ENTITIES@
, @INIT_<имя программы>_ENTITY_CONNECTIONS@
и @INIT_<имя программы>_ENTITY_CONNECTIONS+@
, используемые в файле init.yaml.in
, автоматически создают в init-описании словари IPC-каналов, которые обеспечивают статическое создание IPC-каналов от процессов, созданных на основе исполняемых файлов, скомпонованных с динамическими библиотеками, к процессу программы BlobContainer
. (Процесс программы BlobContainer
получает имя kl.bc.BlobContainer
, а IPC-каналы получают имя kl.BlobContainer
.) При этом для процессов, которые работают с динамическими библиотеками, используя только интерфейс POSIX, словари IPC-каналов к процессу программы BlobContainer
автоматически не создаются, и, чтобы требуемые IPC-каналы были созданы статически, нужно создать эти словари вручную (эти IPC-каналы должны иметь имя kl.BlobContainer
).
Если программа BlobContainer
включена в решение вручную, и требуется статически создать IPC-каналы от процессов, использующих динамические библиотеки, к процессу программы BlobContainer
, то нужно вручную создать словари необходимых IPC-каналов в init-описании. По умолчанию IPC-канал к процессу программы BlobContainer
имеет имя kl.BlobContainer
, но это имя можно изменить через переменную окружения _BLOB_CONTAINER_BACKEND
. Эту переменную нужно задать как для процесса BlobContainer
, так и для процессов, использующих динамические библиотеки.
Переменная окружения _BLOB_CONTAINER_BACKEND
задает не только имя статически создаваемых IPC-каналов к процессу программы BlobContainer
, но и имя службы, публикуемое на сервере имен, которое используется для динамического создания IPC-каналов к процессу программы BlobContainer
. Это удобно использовать, когда запущено одновременно несколько процессов программы BlobContainer
(например, с целью изоляции собственных динамических библиотек от сторонних), и разные процессы, использующие динамические библиотеки, должны взаимодействовать через IPC с разными процессами программы BlobContainer
. В таком случае для разных процессов программы BlobContainer
нужно задать разные значения переменной окружения _BLOB_CONTAINER_BACKEND
, а затем использовать эти значения для переменной окружения _BLOB_CONTAINER_BACKEND
процессов, использующих динамические библиотеки, выбирая конкретное значение в зависимости того, с каким именно процессом программы BlobContainer
требуется динамически создать IPC-канал.
Пример использования переменной окружения _BLOB_CONTAINER_BACKEND
в файле init.yaml.in
:
Пример использования переменной окружения _BLOB_CONTAINER_BACKEND
в CMake
-командах:
Сборка динамических библиотек
Чтобы выполнить сборку динамической библиотеки, нужно использовать следующую CMake
-команду:
Также можно выполнить сборку динамической библиотеки следующей CMake
-командой:
При этом shell-команду cmake
нужно вызвать с параметром -D BUILD_SHARED_LIBS=YES
. (Если вызвать shell-команду cmake
без параметра -D BUILD_SHARED_LIBS=YES
, будет выполнена сборка статической библиотеки.)
Пример:
По умолчанию имя файла библиотеки совпадает с именем цели сборки, заданным через параметр CMake
-команды add_library()
. Имя файла библиотеки можно изменить, используя CMake
-команду set_target_properties()
. Это можно использовать, чтобы имя файла библиотеки было одинаковым для ее динамического и статического варианта.
Пример:
Динамическая библиотека может быть скомпонована с другими статическими и динамическими библиотеками CMake
-командой target_link_libraries()
. При этом статические библиотеки должны быть собраны с флагом -fPIC
. Этот флаг применяется при сборке статической библиотеки, если используется следующая CMake
-команда:
Добавление динамических библиотек в решение на базе KasperskyOS
Чтобы добавить динамические библиотеки в решение на базе KasperskyOS, существует два способа: с автоматическим и ручным поиском динамических библиотек, от которых зависят программы решения.
Способ с автоматическим поиском динамических библиотек
Нужно использовать параметры PACK_DEPS_COPY_ONLY ON
, PACK_DEPS_LIBS_PATH
и PACK_DEPS_COPY_TARGET
в CMake
-командах build_kos_qemu_image()
и build_kos_hw_image()
.
Динамические библиотеки, которые загружаются в память вызовом функции dlopen()
интерфейса POSIX, не будут найдены автоматическим поиском.
Пример 1:
Пример 2:
Способ с ручным поиском динамических библиотек
Нужно самостоятельно выполнить поиск динамических библиотек, от которых зависят программы решения. Это позволяет добавить в решение даже те динамические библиотеки, которые загружаются в память вызовом функции dlopen()
интерфейса POSIX.
Пример 1:
Пример 2: