KasperskyOS Community Edition 1.2
Содержание
Использование динамических библиотек
В решении на базе KasperskyOS можно использовать динамические библиотеки (файлы *.so
). По сравнению со статическими библиотеками (файлами *.a
) динамические библиотеки дают следующие преимущества:
- Экономия оперативной памяти.
Несколько процессов могут использовать один экземпляр динамической библиотеки. Также программа и динамические библиотеки в одном процессе могут использовать один экземпляр динамической библиотеки.
Динамические библиотеки могут загружаться в память и выгружаться из нее по инициативе программ, которые их используют.
- Удобство обновления ПО.
Обновление динамической библиотеки распространяется на все зависимые от нее программы и динамические библиотеки без их повторной сборки.
- Возможность реализовать механизм плагинов.
Плагины для компонентов решения представляют собой динамические библиотеки.
- Совместное использование кода и данных.
Один экземпляр динамической библиотеки может совместно использоваться несколькими процессами, а также программой и динамическими библиотеками в одном процессе. Это позволяет, например, централизованно управлять множественным доступом к ресурсам или хранить общие данные.
Динамические библиотеки поставляются в составе KasperskyOS SDK, а также могут быть созданы разработчиком решения на базе KasperskyOS. Работоспособность сторонних динамических библиотек не гарантируется.
В настоящее время из-за технических ограничений в решении на базе KasperskyOS нельзя использовать libc.so
и libpthread.so
.
Условия, необходимые для использования динамических библиотек
Чтобы использовать динамические библиотеки в решении на базе KasperskyOS, нужно выполнить следующие условия:
- Процессы, использующие динамические библиотеки, должны иметь доступ к файловым системам, в которых хранятся файлы динамических библиотек. Доступ к файловым системам обеспечивается VFS, которая может исполняться в контексте процессов, использующих динамические библиотеки, а также может быть отдельным процессом. VFS и другое ПО, с помощью которого VFS работает с накопителем (например драйвер накопителя), не должны использовать динамические библиотеки.
- Тулчейн должен поддерживать динамическую компоновку.
В составе KasperskyOS SDK поставляется отдельный тулчейн для каждой поддерживаемой архитектуры процессора. Требуемый тулчейн может не поддерживать динамическую компоновку. Чтобы проверить, что динамическая компоновка поддерживается, нужно использовать в корневом файле
CMakeLists.txt
CMake
-командуget_property()
следующим образом:get_property(CAN_SHARED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) if(CAN_SHARED) message(STATUS "Dynamic linking is supported.") endif() - Исполняемый код программ, использующих динамические библиотеки, должен быть собран с флагом
-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. Динамическая библиотека может быть скомпонована с другими динамическими библиотеками, поэтому программа зависит не только от непосредственно скомпонованной с ней динамической библиотеки, но и от всего графа зависимостей этой библиотеки. Динамическая библиотека загружается в память совместно с всеми динамическими библиотеками, от которых зависит.Если системная программа
BlobContainer
включена в решение на базе KasperskyOS, то один экземпляр динамической библиотеки загружается в разделяемую память независимо от того, сколько процессов использует эту библиотеку. (Точнее, в разделяемую память загружается только часть динамической библиотеки, включающая код и доступные только на чтение данные. Другая часть динамической библиотеки в любом случае загружается в память каждого процесса, который использует эту библиотеку.) Если системная программаBlobContainer
не включена в решение, то отдельные экземпляры динамической библиотеки загружаются в память процессов, использующих эту библиотеку. Динамическая библиотека, от которой зависит нескольких других динамических библиотек, загружается в разделяемую память или память процесса в единственном экземпляре.Если задать через переменную окружения
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. Динамическая библиотека, загруженная в память процесса вызовом функцииdlopen()
, выгружается вызовом функцииdlclose()
. Динамическая библиотека, скомпонованная с программой, не может быть выгружена из памяти до завершения процесса, в контексте которого эта программа исполняется. Динамическая библиотека, скомпонованная с другими динамическими библиотеками, выгружается из памяти после выгрузки всех библиотек, которые зависят от нее, либо после завершения процесса.
Включение системной программы BlobContainer в решение на базе KasperskyOS
Если программа BlobContainer
поставляется в составе KasperskyOS SDK, ее необходимо включить в решение, в котором используются динамические библиотеки. Чтобы проверить, поставляется ли программа BlobContainer
в составе KasperskyOS SDK, нужно убедиться в наличии исполняемого файла sysroot-*-kos/bin/BlobContainer
.
Программа 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
нужно включить в решение вручную.
В случае применения программы BlobContainer
должны быть созданы 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
-командах:
Если используется программа BlobContainer
, то VFS, работающая с файлами динамических библиотек, должна быть отдельным процессом. Также должен быть создан IPC-канал от процесса программы BlobContainer
к процессу VFS.
Сборка динамических библиотек
Для сборки динамических библиотек требуется использовать тулчейн, который поддерживает динамическую компоновку.
Чтобы выполнить сборку динамической библиотеки, нужно использовать следующую 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()
.
Пример:
Динамические библиотеки, от которых зависят программы решения, будут добавлены в образ накопителя (например, с файловой системой ext4), который будет включен в образ решения.
Динамические библиотеки, которые загружаются в память вызовом функции dlopen()
интерфейса POSIX, не попадут в образ решения.
Система сборки выполняет следующие действия:
- Осуществляет поиск динамических библиотек и копирует эти библиотеки в директорию, путь к которой указан в параметре
PACK_DEPS_LIBS_PATH
CMake
-командbuild_kos_qemu_image()
иbuild_kos_hw_image()
. (Чтобы найденные динамические библиотеки попали в образ накопителя, эта директория должна находиться в файловой системе, которая будет помещена в образ накопителя.) - Создает образ накопителя, который включает директорию с динамическими библиотеками.
Чтобы создать образ накопителя, нужно использовать
CMake
-командуadd_custom_command()
. Цель, указанная в параметреDEPENDS
CMake
-командыadd_custom_command()
, означает создание образа накопителя. Цель, указанная в параметреPACK_DEPS_COPY_TARGET
CMake
-командbuild_kos_qemu_image()
иbuild_kos_hw_image()
, означает копирование динамических библиотек. Чтобы образ накопителя был создан только после завершения копирования динамических библиотек, нужно использоватьCMake
-командуadd_dependencies()
. - Добавляет образ накопителя в образ решения.
Чтобы добавить образ накопителя в образ решения, нужно указать полный путь к образу накопителя в параметре
IMAGE_FILES
CMake
-командbuild_kos_qemu_image()
иbuild_kos_hw_image()
.