]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dlopen: add header-only public API for FDO .note.dlopen ELF metadata
authorChristian Brauner <brauner@kernel.org>
Wed, 11 Mar 2026 14:54:54 +0000 (15:54 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 18 Mar 2026 10:28:11 +0000 (10:28 +0000)
Expose ELF note dlopen annotation macros as a public header-only API in
sd-dlopen.h. This allows any project to embed .note.dlopen metadata in
their ELF binaries by simply including the header - no runtime linkage
against libsystemd is required.

The header provides SD_ELF_NOTE_DLOPEN() and associated macros/constants
implementing the ELF dlopen metadata specification for declaring optional
shared library dependencies loaded via dlopen() at runtime.

Signed-off-by: Christian Brauner <brauner@kernel.org>
src/systemd/meson.build
src/systemd/sd-dlopen.h [new file with mode: 0644]

index c3d2c1befb71a804454d64bcebcc7e5794afa564..d7335cee558de24a0e90f30c84d30d93dfdcd0d4 100644 (file)
@@ -6,6 +6,7 @@ _systemd_headers = [
         'sd-bus-vtable.h',
         'sd-daemon.h',
         'sd-device.h',
+        'sd-dlopen.h',
         'sd-event.h',
         'sd-gpt.h',
         'sd-hwdb.h',
diff --git a/src/systemd/sd-dlopen.h b/src/systemd/sd-dlopen.h
new file mode 100644 (file)
index 0000000..b3af9b7
--- /dev/null
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef foosddlopenhfoo
+#define foosddlopenhfoo
+
+/***
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <https://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _SD_PASTE
+#  define _SD_PASTE_INNER(a, b) a##b
+#  define _SD_PASTE(a, b) _SD_PASTE_INNER(a, b)
+#endif
+
+#ifndef _SD_UNIQ
+#  ifdef __COUNTER__
+#    define _SD_UNIQ _SD_PASTE(_sd_uniq_, __COUNTER__)
+#  else
+#    define _SD_UNIQ _SD_PASTE(_sd_uniq_, __LINE__)
+#  endif
+#endif
+
+/* ELF note macros implementing the FDO .note.dlopen standard.
+ *
+ * These macros embed metadata in an ELF binary's .note.dlopen section,
+ * declaring optional shared library dependencies that are loaded via
+ * dlopen() at runtime. Package managers and build systems can read
+ * these notes to discover runtime dependencies not visible in ELF
+ * DT_NEEDED entries.
+ *
+ * Usage:
+ *
+ *   SD_ELF_NOTE_DLOPEN("myfeature", "Feature description",
+ *                       SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+ *                       "libfoo.so.1");
+ *
+ * See SD_ELF_NOTE_DLOPEN(3) for details.
+ */
+
+#define SD_ELF_NOTE_DLOPEN_VENDOR "FDO"
+#define SD_ELF_NOTE_DLOPEN_TYPE UINT32_C(0x407c0c0a)
+#define SD_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED    "required"
+#define SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended"
+#define SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED   "suggested"
+
+#define _SD_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(SD_ELF_NOTE_DLOPEN_VENDOR)];                   \
+                _Alignas(sizeof(uint32_t)) char dlopen_json[sizeof(json)];      \
+        } variable_name = {                                                     \
+                .nhdr = {                                                       \
+                        .n_namesz = sizeof(SD_ELF_NOTE_DLOPEN_VENDOR),          \
+                        .n_descsz = sizeof(json),                               \
+                        .n_type   = SD_ELF_NOTE_DLOPEN_TYPE,                    \
+                },                                                              \
+                .name = SD_ELF_NOTE_DLOPEN_VENDOR,                              \
+                .dlopen_json = json,                                            \
+        }
+
+#define _SD_SONAME_ARRAY1(a) "[\"" a "\"]"
+#define _SD_SONAME_ARRAY2(a, b) "[\"" a "\",\"" b "\"]"
+#define _SD_SONAME_ARRAY3(a, b, c) "[\"" a "\",\"" b "\",\"" c "\"]"
+#define _SD_SONAME_ARRAY4(a, b, c, d) "[\"" a "\",\"" b "\",\"" c "\",\"" d "\"]"
+#define _SD_SONAME_ARRAY5(a, b, c, d, e) "[\"" a "\",\"" b "\",\"" c "\",\"" d "\",\"" e "\"]"
+#define _SD_SONAME_ARRAY_GET(_1,_2,_3,_4,_5,NAME,...) NAME
+#define _SD_SONAME_ARRAY(...) _SD_SONAME_ARRAY_GET(__VA_ARGS__, _SD_SONAME_ARRAY5, _SD_SONAME_ARRAY4, _SD_SONAME_ARRAY3, _SD_SONAME_ARRAY2, _SD_SONAME_ARRAY1)(__VA_ARGS__)
+
+#define SD_ELF_NOTE_DLOPEN(feature, description, priority, ...) \
+        _SD_ELF_NOTE_DLOPEN("[{\"feature\":\"" feature "\",\"description\":\"" description "\",\"priority\":\"" priority "\",\"soname\":" _SD_SONAME_ARRAY(__VA_ARGS__) "}]", _SD_PASTE(_sd_elf_note_dlopen_, _SD_UNIQ))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif