Contents
Using dynamic libraries
Dynamic libraries (*.so
files) can be used in a KasperskyOS-based solution. Compared to static libraries (*.a
files), dynamic libraries provide the following advantages:
- Efficient use of RAM.
Multiple processes can use the same instance of a dynamic library. Also, an executable file and dynamic libraries in one process can use the same instance of a dynamic library.
Dynamic libraries can be loaded into memory and unloaded from memory on the initiative of the programs that use them.
- Convenient software updates.
A dynamic library update is applied to all executable files and dynamic libraries dependent on this dynamic library without having to rebuild them.
- Capability to implement a mechanism for plug-ins.
Plug-ins for solution components consist of dynamic libraries.
- Shared use of code and data.
One instance of a dynamic library can be concurrently used by multiple processes, and by an executable file and dynamic libraries in one process. This enables centralized management of multi-access to resources or storage of shared data, for example.
Dynamic libraries are provided in KasperskyOS Community Edition, and can also be created by a KasperskyOS-based solution developer. Normal operation of third-party dynamic libraries cannot be guaranteed.
Due to current technical limitations, libc.so
and libpthread.so
cannot be used in a KasperskyOS-based solution.
In this section Prerequisites for using dynamic libraries Life cycle of a dynamic library Including the BlobContainer system program in a KasperskyOS-based solution |
Prerequisites for using dynamic libraries
To use dynamic libraries in a KasperskyOS-based solution, the following conditions must be met:
- Processes that use dynamic libraries must have access to the file systems in which the files of the dynamic libraries are stored. Access to file systems is provided by VFS, which is a separate process. The dynamic libraries must not be used by VFS or other software that is used by VFS to work with storage (such as a storage driver).
- The system program
BlobContainer
must be included in the solution. - Executable files that use dynamic libraries must be built with the
-rdynamic
flag (with dynamic linking).The
CMake
initialize_platform()
command causes this flag to be used automatically for building all executable files defined viaCMake
add_executable()
commands.
If the CMake
command initialize_platform(FORCE_STATIC)
is specified in the CMakeLists.txt
root file, the toolchain performs static linking of executable files.
The CMake
project_static_executable_header_default()
command affects the build of executable files defined via subsequent CMake
add_executable()
commands in one CMakeLists.txt
file. The toolchain performs static linking of these executable files.
The CMake
platform_target_force_static()
command affects the build of one executable file defined via the CMake
add_executable()
command. The toolchain performs static linking of this executable file.
The executable file that is built with the -rdynamic
flag is linked to a static library if a dynamic library is not found. For example, if the CMake
target_link_libraries
(client -lm)
command is being used, the executable file of the client
program is linked to the static library libm.a
if the dynamic library libm.so
is not found.
Life cycle of a dynamic library
The life cycle of a dynamic library includes the following phases:
- Loading into memory.
A dynamic library linked to an executable file is loaded into shared memory upon startup of the process that was created based on this executable file. A process can also load a dynamic library into shared memory by calling the
dlopen()
function of the POSIX interface. A dynamic library may be linked to other dynamic libraries, so an executable file depends not only on the dynamic library directly linked to it, but also depends on the entire dependency graph of this library. A dynamic library is loaded into shared memory together with all of the dynamic libraries that it depends on.One instance of a dynamic library is loaded into shared memory regardless of how many processes are using this library. (More specifically, only the part of the dynamic library that includes code and read-only data is loaded into shared memory. The other part of the dynamic library is loaded into the memory of each process that uses this library.) A dynamic library on which several other dynamic libraries depend is loaded into shared memory in a single instance.
If a list of dynamic libraries is defined through the
LD_PRELOAD
environment variable, these dynamic libraries will be loaded into shared memory even if the executable file is not dependent on them. (List items must be absolute or relative paths to dynamic libraries separated by a colon, for example:LD_PRELOAD=libmalloc.so:libfree.so:/usr/somepath/lib/libfoo.so
.) The functions that are exported by the dynamic libraries specified inLD_PRELOAD
replace the identically named functions that are exported by other dynamic libraries. This can be used for debugging purposes if you need to replace functions imported from dynamic libraries.The dynamic library loader searches for dynamic libraries in the following order:
- Absolute paths defined through the
LD_LIBRARY_PATH
environment variable.Paths must be separated by a colon, for example:
LD_LIBRARY_PATH=/usr/lib:/home/user/lib
. - Absolute paths defined in the
DT_RUNPATH
orDT_RPATH
field of the.dynamic
section of executable files and dynamic libraries.Linking of executable files and dynamic libraries may include defined paths that the dynamic library loader will search. (For example, this can be done through the
INSTALL_RPATH
property in theCMake
commandset_target_properties()
.) Paths used to search for dynamic libraries are stored in theDT_RUNPATH
orDT_RPATH
field of the.dynamic
section. This field may be in executable files linked to dynamic libraries and in dynamic libraries linked to other dynamic libraries. - Path
/lib
.
The dynamic library loader searches in this same order if a relative path to a dynamic library is specified in the
filename
parameter of thedlopen()
function or in theLD_PRELOAD
environment variable. If the absolute path is specified, the loader puts the dynamic library into shared memory without performing a search. - Absolute paths defined through the
- Use by a process (or processes).
- Unloading from memory.
A dynamic library is unloaded from shared memory when all processes using this library have terminated or called the
dlclose()
function of the POSIX interface. A dynamic library linked to an executable file cannot be unloaded from shared memory until termination of the process that was created based on this executable file. A dynamic library that is linked to other dynamic libraries is unloaded from shared memory after all libraries that depend on it are unloaded.
Including the BlobContainer system program in a KasperskyOS-based solution
If a solution uses dynamic libraries, the system program BlobContainer
must be included in this solution (this system program is provided by the executable file sysroot-aarch64-kos/bin/BlobContainer
from KasperskyOS Community Edition).
The BlobContainer
program can be included in a solution either automatically or manually. This program is automatically included in a solution by running the CMake
commands build_kos_qemu_image()
and build_kos_hw_image()
if at least one executable file in the solution is linked to a dynamic library. (To disable automatic inclusion of the BlobContainer
program in a solution, you need to add the NO_AUTO_BLOB_CONTAINER
value to the parameters of the CMake
commands build_kos_qemu_image()
and build_kos_hw_image()
.) If programs in a solution work with dynamic libraries using only a POSIX interface (the dlopen()
, dlsym()
, dlerror()
, and dlclose()
functions), the BlobContainer
program needs to be manually included in the solution.
The VFS working with files of dynamic libraries must be a separate process. You need to create an IPC channel from the process of the BlobContainer
program to the VFS process.
You must create IPC channels from the processes using dynamic libraries to the process of the BlobContainer
program. These IPC channels can be created statically or dynamically. If a statically created IPC channel is not available, the client and server parts of the BlobContainer
program attempt to dynamically create an IPC channel using the name server.
If the BlobContainer
program is automatically included in a solution, the @INIT_EXTERNAL_ENTITIES@
, @INIT_<program name>_ENTITY_CONNECTIONS@
and @INIT_<program name>_ENTITY_CONNECTIONS+@
macros used in the init.yaml.in
file automatically create within the init description dictionaries of IPC channels that enable static creation of IPC channels from processes created based on executable files linked to dynamic libraries to the process of the BlobContainer
program. (The process of the BlobContainer
program receives the name kl.bc.BlobContainer
, while the IPC channels receive the name kl.BlobContainer
.) However, dictionaries of IPC channels to the BlobContainer
program process are not automatically created for processes that work with dynamic libraries using only a POSIX interface. To ensure that the required IPC channels are statically created, these dictionaries must be manually created (these IPC channels must have the name kl.BlobContainer
).
If the BlobContainer
program is manually included in the solution and you need to statically create IPC channels from processes using dynamic libraries to the BlobContainer
program process, you must manually create dictionaries of the required IPC channels in the init description. By default, the IPC channel to the BlobContainer
program process has the name kl.BlobContainer
. However, this name can be changed through the environment variable _BLOB_CONTAINER_BACKEND
. This variable must be defined for the BlobContainer
process and for processes using dynamic libraries.
The environment variable _BLOB_CONTAINER_BACKEND
defines not only the name of statically created IPC channels to the BlobContainer
program process, but also defines the endpoint name that is published on the name server and used to dynamically create IPC channels to the BlobContainer
program process. This is convenient when multiple processes of the BlobContainer
program are running simultaneously (for example, to isolate its own dynamic libraries from external ones), and when different processes using dynamic libraries must interact over IPC with different processes of the BlobContainer
program. In this case, you need to define different values for the environment variable _BLOB_CONTAINER_BACKEND
for different processes of the BlobContainer
program, and then use these values for the environment variable _BLOB_CONTAINER_BACKEND
for processes using dynamic libraries. The specific value must be selected depending on the specific process of the BlobContainer
program that requires the dynamically created IPC channel.
Example use of the environment variable _BLOB_CONTAINER_BACKEND
in the init.yaml.in
file:
Example use of the environment variable _BLOB_CONTAINER_BACKEND
in CMake
commands:
Building dynamic libraries
To build a dynamic library, you need to use the following CMake
command:
You can also build a dynamic library by using the following CMake
command:
The cmake
shell command must be called with the -D BUILD_SHARED_LIBS=YES
parameter. (If the cmake
shell command is called without the -D BUILD_SHARED_LIBS=YES
parameter, a static library will be built.)
Example:
By default, the library file name matches the name of the build target defined via the parameter of the CMake
add_library()
command. The library file name can be changed by using the CMake
set_target_properties()
command. This can be done to make the library file name identical for its dynamic and static variants.
Example:
A dynamic library can be linked to other static and dynamic libraries by using the CMake
target_link_libraries()
command. In this case, static libraries must be built with the -fPIC
flag. This flag is applied when building a static library if the following CMake
command is used:
Adding dynamic libraries to a KasperskyOS-based solution
There are two ways to add dynamic libraries to a KasperskyOS-based solution: by either automatic or manual search for the dynamic libraries required by the solution programs.
Automatic search for dynamic libraries
Use the PACK_DEPS_COPY_ONLY ON
, PACK_DEPS_LIBS_PATH
, and PACK_DEPS_COPY_TARGET
parameters in the CMake
commands build_kos_qemu_image()
and build_kos_hw_image()
.
Dynamic libraries that are loaded into memory by calling the dlopen()
function of the POSIX interface will not be found by an automatic search.
Example 1:
Example 2:
Manual search for dynamic libraries
You need to independently search for dynamic libraries required by the solution programs. This way, even dynamic libraries that were loaded into memory by calling the dlopen()
function of the POSIX interface can be added to a solution.
Example 1:
Example 2: