mirror of
https://github.com/systemd/systemd.git
synced 2025-02-09 13:57:42 +03:00
Merge pull request #32234 from poettering/dlopen-name-elf-note
Expose dlopen() dependencies in an ELF section, and add spec for it
This commit is contained in:
commit
344ededcea
89
docs/ELF_DLOPEN_METADATA.md
Normal file
89
docs/ELF_DLOPEN_METADATA.md
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
title: Dlopen Metadata for ELF Files
|
||||
category: Interfaces
|
||||
layout: default
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
---
|
||||
|
||||
# `dlopen()` Metadata for ELF Files
|
||||
|
||||
*Intended audience: hackers working on packaging ELF files that use dlopen to load libraries.*
|
||||
|
||||
## Motivation
|
||||
|
||||
Using `dlopen()` to load optional dependencies brings several advantages: programs can gracefully downgrade
|
||||
a feature when a library is not available, and the shared library is only loaded into the process (and its
|
||||
ELF constructors are run) only when the requested feature is actually used. But it also has some drawbacks,
|
||||
and the main one is that it is harder to track a program's dependencies, since unlike build-time dynamic
|
||||
linking there will not be a mention in the ELF metadata. This specification aims to solve this problem by
|
||||
providing a standardized specification for a custom ELF note that can be used to list `dlopen()`
|
||||
dependencies.
|
||||
|
||||
## Implementation
|
||||
|
||||
This document will attempt to define a common metadata format specification, so that multiple implementers
|
||||
might use it when coding upstream software, and packagers might use it when building packages and setting
|
||||
dependencies.
|
||||
|
||||
The metadata will be embedded in a series of new, 4-byte-aligned, allocated, 0-padded, read-only ELF header
|
||||
sections, in a JSON array containing name-value objects, either one ELF note per dependency or as a single
|
||||
note listing multiple dependencies in the top-level array. Implementers working on parsing ELF files should
|
||||
not assume a specific list of names, but parse anything that is included in the section, and should look for
|
||||
the note using the `note type`. Implementers working on build tools should strive to use the same names, for
|
||||
consistency. The most common will be listed here.
|
||||
|
||||
* Section header
|
||||
|
||||
```
|
||||
SECTION: `.note.dlopen`
|
||||
note type: `0x407c0c0a`
|
||||
Owner: `FDO` (FreeDesktop.org)
|
||||
Value: an array of JSON objects encoded as a zero-terminated UTF-8 string
|
||||
```
|
||||
|
||||
* JSON payload
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"soname": ["libfoo.so.1"],
|
||||
"feature": "foo",
|
||||
"description": "Enables the foo feature",
|
||||
"priority": "recommended"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The format is a single JSON array containing objects, encoded as a zero-terminated `UTF-8` string. Each key
|
||||
in each object shall be unique as per recommendations of [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259#section-4).
|
||||
Strings shall not contain any control characters or use `\uXXX` escaping.
|
||||
|
||||
Reference implementations of [packaging tools for `.deb` and `.rpm`](https://github.com/systemd/package-notes)
|
||||
are available, and provide macros/helpers to parse the note when building packages and adding dependencies.
|
||||
|
||||
## Well-known keys
|
||||
|
||||
The metadata format is intentionally extensible, so that upstreams and later revisions of this spec can add
|
||||
their own information. The 'soname' array is required, with at least one element, everything else is
|
||||
optional. If alternative soname versions for the same library are supported at the same time, an array can
|
||||
be used, listing the most preferred first, and parsers are expected to select only the first one that is
|
||||
available on the system, as it is a mechanism to specify alternatives. If the `priority` field is used, it
|
||||
must follow the specification and use one of the values specified in the table. If it is not specified, a
|
||||
parser should assume 'recommended' if a priority is needed. If the `feature` field is used, it will identify
|
||||
an individual feature, and multiple entries using the same `feature` denote functionality that requires all
|
||||
of the libraries they specify in order to be enabled.
|
||||
|
||||
| Key name | Key type | Mandatory | Key description | Example value |
|
||||
|-------------|----------------------------|-----------|--------------------------------------------------------------------------|----------------------------------|
|
||||
| soname | array of strings | yes | The library names loaded by `dlopen()` | [ "libfoo.so.1", "libfoo.so.0" ] |
|
||||
| feature | string | no | A keyword identifying the feature that the library contributes to enable | "foo" |
|
||||
| description | string | no | A human-readable text string describing the feature | "Enables the foo feature" |
|
||||
| priority | string | no | The priority of the feature, one of: required, recommended, suggested | "recommended" |
|
||||
|
||||
### Priority definition
|
||||
|
||||
| Priority | Semantics |
|
||||
|-------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| required | Core functionality needs the dependency, the binary will not work if it cannot be found |
|
||||
| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided |
|
||||
| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations |
|
@ -1418,6 +1418,15 @@ elif compression == 'lz4' and not liblz4.found()
|
||||
elif compression == 'xz' and not libxz.found()
|
||||
error('default-compression=xz requires xz')
|
||||
endif
|
||||
# In the dlopen ELF note we save the default compression library with a
|
||||
# higher priority, so that packages can give it priority over the
|
||||
# secondary libraries.
|
||||
conf.set_quoted('COMPRESSION_PRIORITY_ZSTD',
|
||||
compression == 'zstd' ? 'recommended' : 'suggested')
|
||||
conf.set_quoted('COMPRESSION_PRIORITY_LZ4',
|
||||
compression == 'lz4' ? 'recommended' : 'suggested')
|
||||
conf.set_quoted('COMPRESSION_PRIORITY_XZ',
|
||||
compression == 'xz' ? 'recommended' : 'suggested')
|
||||
conf.set('DEFAULT_COMPRESSION', 'COMPRESSION_@0@'.format(compression.to_upper()))
|
||||
|
||||
libarchive = dependency('libarchive',
|
||||
|
@ -129,6 +129,11 @@ bool compression_supported(Compression c) {
|
||||
|
||||
#if HAVE_XZ
|
||||
int dlopen_lzma(void) {
|
||||
ELF_NOTE_DLOPEN("lzma",
|
||||
"Support lzma compression in journal and coredump files",
|
||||
COMPRESSION_PRIORITY_XZ,
|
||||
"liblzma.so.5");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&lzma_dl,
|
||||
"liblzma.so.5", LOG_DEBUG,
|
||||
@ -186,6 +191,11 @@ int compress_blob_xz(const void *src, uint64_t src_size,
|
||||
|
||||
#if HAVE_LZ4
|
||||
int dlopen_lz4(void) {
|
||||
ELF_NOTE_DLOPEN("lz4",
|
||||
"Support lz4 compression in journal and coredump files",
|
||||
COMPRESSION_PRIORITY_LZ4,
|
||||
"liblz4.so.1");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&lz4_dl,
|
||||
"liblz4.so.1", LOG_DEBUG,
|
||||
@ -242,6 +252,11 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
|
||||
|
||||
#if HAVE_ZSTD
|
||||
int dlopen_zstd(void) {
|
||||
ELF_NOTE_DLOPEN("zstd",
|
||||
"Support zstd compression in journal and coredump files",
|
||||
COMPRESSION_PRIORITY_ZSTD,
|
||||
"libzstd.so.1");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&zstd_dl,
|
||||
"libzstd.so.1", LOG_DEBUG,
|
||||
|
@ -39,3 +39,44 @@ int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_l
|
||||
/* libbpf is a bit confused about type-safety and API compatibility. Provide a macro that can tape over that mess. Sad. */
|
||||
#define DLSYM_ARG_FORCE(arg) \
|
||||
&sym_##arg, STRINGIFY(arg)
|
||||
|
||||
#define ELF_NOTE_DLOPEN_VENDOR "FDO"
|
||||
#define ELF_NOTE_DLOPEN_TYPE UINT32_C(0x407c0c0a)
|
||||
#define ELF_NOTE_DLOPEN_PRIORITY_REQUIRED "required"
|
||||
#define ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended"
|
||||
#define ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED "suggested"
|
||||
|
||||
/* Add an ".note.dlopen" ELF note to our binary that declares our weak dlopen() dependency. This
|
||||
* information can be read from an ELF file via "readelf -p .note.dlopen" or an equivalent command. */
|
||||
#define _ELF_NOTE_DLOPEN(json, variable_name) \
|
||||
__attribute__((used, section(".note.dlopen"))) _Alignas(sizeof(uint32_t)) static const struct { \
|
||||
struct { \
|
||||
uint32_t n_namesz, n_descsz, n_type; \
|
||||
} nhdr; \
|
||||
char name[sizeof(ELF_NOTE_DLOPEN_VENDOR)]; \
|
||||
_Alignas(sizeof(uint32_t)) char dlopen_json[sizeof(json)]; \
|
||||
} variable_name = { \
|
||||
.nhdr = { \
|
||||
.n_namesz = sizeof(ELF_NOTE_DLOPEN_VENDOR), \
|
||||
.n_descsz = sizeof(json), \
|
||||
.n_type = ELF_NOTE_DLOPEN_TYPE, \
|
||||
}, \
|
||||
.name = ELF_NOTE_DLOPEN_VENDOR, \
|
||||
.dlopen_json = json, \
|
||||
}
|
||||
|
||||
#define _SONAME_ARRAY1(a) "[\""a"\"]"
|
||||
#define _SONAME_ARRAY2(a, b) "[\""a"\",\""b"\"]"
|
||||
#define _SONAME_ARRAY3(a, b, c) "[\""a"\",\""b"\",\""c"\"]"
|
||||
#define _SONAME_ARRAY4(a, b, c, d) "[\""a"\",\""b"\",\""c"\"",\""d"\"]"
|
||||
#define _SONAME_ARRAY5(a, b, c, d, e) "[\""a"\",\""b"\",\""c"\"",\""d"\",\""e"\"]"
|
||||
#define _SONAME_ARRAY_GET(_1,_2,_3,_4,_5,NAME,...) NAME
|
||||
#define _SONAME_ARRAY(...) _SONAME_ARRAY_GET(__VA_ARGS__, _SONAME_ARRAY5, _SONAME_ARRAY4, _SONAME_ARRAY3, _SONAME_ARRAY2, _SONAME_ARRAY1)(__VA_ARGS__)
|
||||
|
||||
/* The 'priority' must be one of 'required', 'recommended' or 'suggested' as per specification, use the
|
||||
* macro defined above to specify it.
|
||||
* Multiple sonames can be passed and they will be automatically contructed into a json array (but note that
|
||||
* due to preprocessor language limitations if more than the limit defined above is used, a new
|
||||
* _SONAME_ARRAY<X+1> will need to be added). */
|
||||
#define ELF_NOTE_DLOPEN(feature, description, priority, ...) \
|
||||
_ELF_NOTE_DLOPEN("[{\"feature\":\"" feature "\",\"description\":\"" description "\",\"priority\":\"" priority "\",\"soname\":" _SONAME_ARRAY(__VA_ARGS__) "}]", UNIQ_T(s, UNIQ))
|
||||
|
@ -41,6 +41,11 @@ DLSYM_FUNCTION(gcry_randomize);
|
||||
DLSYM_FUNCTION(gcry_strerror);
|
||||
|
||||
static int dlopen_gcrypt(void) {
|
||||
ELF_NOTE_DLOPEN("gcrypt",
|
||||
"Support for journald forward-sealing",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libgcrypt.so.20");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&gcrypt_dl,
|
||||
"libgcrypt.so.20", LOG_DEBUG,
|
||||
|
@ -16,6 +16,10 @@ DLSYM_FUNCTION(xkb_keymap_new_from_names);
|
||||
DLSYM_FUNCTION(xkb_keymap_unref);
|
||||
|
||||
static int dlopen_xkbcommon(void) {
|
||||
ELF_NOTE_DLOPEN("xkbcommon",
|
||||
"Support for keyboard locale descriptions",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, "libxkbcommon.so.0");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&xkbcommon_dl, "libxkbcommon.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(xkb_context_new),
|
||||
|
@ -76,6 +76,11 @@ int dlopen_bpf(void) {
|
||||
void *dl;
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("bpf",
|
||||
"Support firewalling and sandboxing with BPF",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libbpf.so.1", "libbpf.so.0");
|
||||
|
||||
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
|
||||
|
||||
dl = dlopen("libbpf.so.1", RTLD_LAZY);
|
||||
|
@ -252,6 +252,11 @@ int dlopen_cryptsetup(void) {
|
||||
|
||||
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
|
||||
|
||||
ELF_NOTE_DLOPEN("cryptsetup",
|
||||
"Support for disk encryption, integrity, and authentication",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libcryptsetup.so.12");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG,
|
||||
DLSYM_ARG(crypt_activate_by_passphrase),
|
||||
|
@ -87,6 +87,11 @@ static DLSYM_FUNCTION(gelf_getnote);
|
||||
int dlopen_dw(void) {
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("dw",
|
||||
"Support for backtrace and ELF package metadata decoding from core files",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libdw.so.1");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&dw_dl, "libdw.so.1", LOG_DEBUG,
|
||||
DLSYM_ARG(dwarf_getscopes),
|
||||
@ -130,6 +135,11 @@ int dlopen_dw(void) {
|
||||
int dlopen_elf(void) {
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("elf",
|
||||
"Support for backtraces and reading ELF package metadata from core files",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libelf.so.1");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&elf_dl, "libelf.so.1", LOG_DEBUG,
|
||||
DLSYM_ARG(elf_begin),
|
||||
|
@ -354,6 +354,11 @@ int fw_iptables_add_local_dnat(
|
||||
}
|
||||
|
||||
static int dlopen_iptc(void) {
|
||||
ELF_NOTE_DLOPEN("ip4tc",
|
||||
"Support for firewall rules",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libip4tc.so.2");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&iptc_dl,
|
||||
"libip4tc.so.2", LOG_DEBUG,
|
||||
|
@ -21,6 +21,11 @@ const char *(*sym_idn2_strerror)(int rc) _const_ = NULL;
|
||||
DLSYM_FUNCTION(idn2_to_unicode_8z8z);
|
||||
|
||||
int dlopen_idn(void) {
|
||||
ELF_NOTE_DLOPEN("idn",
|
||||
"Support for internationalized domain names",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libidn2.so.0");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&idn_dl, "libidn2.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(idn2_lookup_u8),
|
||||
@ -39,6 +44,11 @@ int dlopen_idn(void) {
|
||||
_cleanup_(dlclosep) void *dl = NULL;
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("idn",
|
||||
"Support for internationalized domain names",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libidn.so.12", "libidn.so.11");
|
||||
|
||||
if (idn_dl)
|
||||
return 0; /* Already loaded */
|
||||
|
||||
|
@ -30,6 +30,11 @@ DLSYM_FUNCTION(archive_write_set_format_filter_by_ext);
|
||||
DLSYM_FUNCTION(archive_write_set_format_gnutar);
|
||||
|
||||
int dlopen_libarchive(void) {
|
||||
ELF_NOTE_DLOPEN("archive",
|
||||
"Support for decompressing archive files",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libarchive.so.13");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&libarchive_dl,
|
||||
"libarchive.so.13",
|
||||
|
@ -72,6 +72,11 @@ static void fido_log_propagate_handler(const char *s) {
|
||||
int dlopen_libfido2(void) {
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("fido2",
|
||||
"Support fido2 for encryption and authentication",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libfido2.so.1");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&libfido2_dl, "libfido2.so.1", LOG_DEBUG,
|
||||
DLSYM_ARG(fido_assert_allow_cred),
|
||||
|
@ -25,6 +25,11 @@ DLSYM_FUNCTION(kmod_unref);
|
||||
DLSYM_FUNCTION(kmod_validate_resources);
|
||||
|
||||
int dlopen_libkmod(void) {
|
||||
ELF_NOTE_DLOPEN("kmod",
|
||||
"Support for loading kernel modules",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
|
||||
"libkmod.so.2");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&libkmod_dl,
|
||||
"libkmod.so.2",
|
||||
|
@ -20,6 +20,11 @@ DLSYM_FUNCTION(passwdqc_check);
|
||||
DLSYM_FUNCTION(passwdqc_random);
|
||||
|
||||
int dlopen_passwdqc(void) {
|
||||
ELF_NOTE_DLOPEN("passwdqc",
|
||||
"Support for password quality checks",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libpasswdqc.so.1");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&passwdqc_dl, "libpasswdqc.so.1", LOG_DEBUG,
|
||||
DLSYM_ARG(passwdqc_params_reset),
|
||||
|
@ -24,6 +24,11 @@ DLSYM_FUNCTION(pwquality_set_int_value);
|
||||
DLSYM_FUNCTION(pwquality_strerror);
|
||||
|
||||
int dlopen_pwquality(void) {
|
||||
ELF_NOTE_DLOPEN("pwquality",
|
||||
"Support for password quality checks",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libpwquality.so.1");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&pwquality_dl, "libpwquality.so.1", LOG_DEBUG,
|
||||
DLSYM_ARG(pwquality_check),
|
||||
|
@ -27,6 +27,11 @@ const struct hash_ops pcre2_code_hash_ops_free = {};
|
||||
|
||||
int dlopen_pcre2(void) {
|
||||
#if HAVE_PCRE2
|
||||
ELF_NOTE_DLOPEN("pcre2",
|
||||
"Support for regular expressions",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libpcre2-8.so.0");
|
||||
|
||||
/* So here's something weird: PCRE2 actually renames the symbols exported by the library via C
|
||||
* macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is
|
||||
* gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we
|
||||
|
@ -61,6 +61,11 @@ DLSYM_FUNCTION(p11_kit_uri_new);
|
||||
DLSYM_FUNCTION(p11_kit_uri_parse);
|
||||
|
||||
int dlopen_p11kit(void) {
|
||||
ELF_NOTE_DLOPEN("p11-kit",
|
||||
"Support for PKCS11 hardware tokens",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libp11-kit.so.0");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&p11kit_dl,
|
||||
"libp11-kit.so.0", LOG_DEBUG,
|
||||
|
@ -24,6 +24,11 @@ static DLSYM_FUNCTION(QRcode_free);
|
||||
int dlopen_qrencode(void) {
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("qrencode",
|
||||
"Support for generating QR codes",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libqrencode.so.4", "libqrencode.so.3");
|
||||
|
||||
FOREACH_STRING(s, "libqrencode.so.4", "libqrencode.so.3") {
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&qrcode_dl, s, LOG_DEBUG,
|
||||
|
@ -113,6 +113,11 @@ static DLSYM_FUNCTION(Tss2_RC_Decode);
|
||||
int dlopen_tpm2(void) {
|
||||
int r;
|
||||
|
||||
ELF_NOTE_DLOPEN("tpm",
|
||||
"Support for TPM",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libtss2-esys.so.0");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&libtss2_esys_dl, "libtss2-esys.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(Esys_Create),
|
||||
@ -164,12 +169,22 @@ int dlopen_tpm2(void) {
|
||||
if (r < 0)
|
||||
log_debug("libtss2-esys too old, does not include Esys_TR_GetTpmHandle.");
|
||||
|
||||
ELF_NOTE_DLOPEN("tpm",
|
||||
"Support for TPM",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libtss2-rc.so.0");
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&libtss2_rc_dl, "libtss2-rc.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(Tss2_RC_Decode));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ELF_NOTE_DLOPEN("tpm",
|
||||
"Support for TPM",
|
||||
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
||||
"libtss2-mu.so.0");
|
||||
|
||||
return dlopen_many_sym_or_warn(
|
||||
&libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(Tss2_MU_TPM2_CC_Marshal),
|
||||
|
Loading…
x
Reference in New Issue
Block a user