diff options
Diffstat (limited to 'docs/ELF_DLOPEN_METADATA.md')
-rw-r--r-- | docs/ELF_DLOPEN_METADATA.md | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/docs/ELF_DLOPEN_METADATA.md b/docs/ELF_DLOPEN_METADATA.md new file mode 100644 index 0000000..5c3bf1e --- /dev/null +++ b/docs/ELF_DLOPEN_METADATA.md @@ -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 | |