|
1 | | ---- |
2 | | -title: Dlopen Metadata for ELF Files |
3 | | -category: Interfaces |
4 | | -layout: default |
5 | | -SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | ---- |
7 | | - |
8 | | -# `dlopen()` Metadata for ELF Files |
9 | | - |
10 | | -*Intended audience: hackers working on packaging ELF files that use dlopen to load libraries.* |
11 | | - |
12 | | -## Motivation |
13 | | - |
14 | | -Using `dlopen()` to load optional dependencies brings several advantages: programs can gracefully downgrade |
15 | | -a feature when a library is not available, and the shared library is only loaded into the process (and its |
16 | | -ELF constructors are run) only when the requested feature is actually used. But it also has some drawbacks, |
17 | | -and the main one is that it is harder to track a program's dependencies, since unlike build-time dynamic |
18 | | -linking there will not be a mention in the ELF metadata. This specification aims to solve this problem by |
19 | | -providing a standardized specification for a custom ELF note that can be used to list `dlopen()` |
20 | | -dependencies. |
21 | | - |
22 | | -## Implementation |
23 | | - |
24 | | -This document will attempt to define a common metadata format specification, so that multiple implementers |
25 | | -might use it when coding upstream software, and packagers might use it when building packages and setting |
26 | | -dependencies. |
27 | | - |
28 | | -The metadata will be embedded in a series of new, 4-byte-aligned, allocated, 0-padded, read-only ELF header |
29 | | -sections, in a JSON array containing name-value objects, either one ELF note per dependency or as a single |
30 | | -note listing multiple dependencies in the top-level array. Implementers working on parsing ELF files should |
31 | | -not assume a specific list of names, but parse anything that is included in the section, and should look for |
32 | | -the note using the `note type`. Implementers working on build tools should strive to use the same names, for |
33 | | -consistency. The most common will be listed here. |
34 | | - |
35 | | -* Section header |
36 | | - |
37 | | -``` |
38 | | -SECTION: `.note.dlopen` |
39 | | -note type: `0x407c0c0a` |
40 | | -Owner: `FDO` (FreeDesktop.org) |
41 | | -Value: an array of JSON objects encoded as a zero-terminated UTF-8 string |
42 | | -``` |
43 | | - |
44 | | -* JSON payload |
45 | | - |
46 | | -```json |
47 | | -[ |
48 | | - { |
49 | | - "soname": ["libfoo.so.1"], |
50 | | - "feature": "foo", |
51 | | - "description": "Enables the foo feature", |
52 | | - "priority": "recommended" |
53 | | - } |
54 | | -] |
55 | | -``` |
56 | | - |
57 | | -The format is a single JSON array containing objects, encoded as a zero-terminated `UTF-8` string. Each key |
58 | | -in each object shall be unique as per recommendations of [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259#section-4). |
59 | | -Strings shall not contain any control characters or use `\uXXX` escaping. |
60 | | - |
61 | | -Reference implementations of [packaging tools for `.deb` and `.rpm`](https://github.com/systemd/package-notes) |
62 | | -are available, and provide macros/helpers to parse the note when building packages and adding dependencies. |
63 | | - |
64 | | -## Well-known keys |
65 | | - |
66 | | -The metadata format is intentionally extensible, so that upstreams and later revisions of this spec can add |
67 | | -their own information. The 'soname' array is required, with at least one element, everything else is |
68 | | -optional. If alternative soname versions for the same library are supported at the same time, an array can |
69 | | -be used, listing the most preferred first, and parsers are expected to select only the first one that is |
70 | | -available on the system, as it is a mechanism to specify alternatives. If the `priority` field is used, it |
71 | | -must follow the specification and use one of the values specified in the table. If it is not specified, a |
72 | | -parser should assume 'recommended' if a priority is needed. If the `feature` field is used, it will identify |
73 | | -an individual feature, and multiple entries using the same `feature` denote functionality that requires all |
74 | | -of the libraries they specify in order to be enabled. |
75 | | - |
76 | | -| Key name | Key type | Mandatory | Key description | Example value | |
77 | | -|-------------|----------------------------|-----------|--------------------------------------------------------------------------|----------------------------------| |
78 | | -| soname | array of strings | yes | The library names loaded by `dlopen()` | [ "libfoo.so.1", "libfoo.so.0" ] | |
79 | | -| feature | string | no | A keyword identifying the feature that the library contributes to enable | "foo" | |
80 | | -| description | string | no | A human-readable text string describing the feature | "Enables the foo feature" | |
81 | | -| priority | string | no | The priority of the feature, one of: required, recommended, suggested | "recommended" | |
82 | | - |
83 | | -### Priority definition |
84 | | - |
85 | | -| Priority | Semantics | |
86 | | -|-------------|--------------------------------------------------------------------------------------------------------------------------------------| |
87 | | -| required | Core functionality needs the dependency, the binary will not work if it cannot be found | |
88 | | -| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided | |
89 | | -| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations | |
90 | | - |
91 | | -### Displaying `dlopen()` notes |
92 | | - |
93 | | -The raw ELF section can be extracted using `objdump`: |
94 | | -```console |
95 | | -$ objdump -j .note.dlopen -s /usr/lib64/systemd/libsystemd-shared-257.so |
96 | | - |
97 | | -/usr/lib64/systemd/libsystemd-shared-257.so: file format elf64-x86-64 |
98 | | - |
99 | | -Contents of section .note.dlopen: |
100 | | - 0334 04000000 8e000000 0a0c7c40 46444f00 ..........|@FDO. |
101 | | - 0344 5b7b2266 65617475 7265223a 22627066 [{"feature":"bpf |
102 | | - 0354 222c2264 65736372 69707469 6f6e223a ","description": |
103 | | - 0364 22537570 706f7274 20666972 6577616c "Support firewal |
104 | | - 0374 6c696e67 20616e64 2073616e 64626f78 ling and sandbox |
105 | | - 0384 696e6720 77697468 20425046 222c2270 ing with BPF","p |
106 | | - 0394 72696f72 69747922 3a227375 67676573 riority":"sugges |
107 | | - 03a4 74656422 2c22736f 6e616d65 223a5b22 ted","soname":[" |
108 | | - 03b4 6c696262 70662e73 6f2e3122 2c226c69 libbpf.so.1","li |
109 | | - 03c4 62627066 2e736f2e 30225d7d 5d000000 bbpf.so.0"]}]... |
110 | | - 03d4 04000000 9e000000 0a0c7c40 46444f00 ..........|@FDO. |
111 | | -... |
112 | | -``` |
113 | | - |
114 | | -It is more convenient to use a higher level tool: |
115 | | -```console |
116 | | -$ dlopen-notes /usr/lib64/systemd/libsystemd-shared-257.so |
117 | | -# /usr/lib64/systemd/libsystemd-shared-257.so |
118 | | -[ |
119 | | - { |
120 | | - "feature": "archive", |
121 | | - "description": "Support for decompressing archive files", |
122 | | - "priority": "suggested", |
123 | | - "soname": [ |
124 | | - "libarchive.so.13" |
125 | | - ] |
126 | | - }, |
127 | | - { |
128 | | - "feature": "bpf", |
129 | | - "description": "Support firewalling and sandboxing with BPF", |
130 | | - "priority": "suggested", |
131 | | - "soname": [ |
132 | | - "libbpf.so.1", |
133 | | - "libbpf.so.0" |
134 | | - ] |
135 | | - }, |
136 | | -... |
137 | | -``` |
138 | | - |
139 | | -`dlopen-notes` can display the notes grouped in a few different ways. |
140 | | -One option is to filter the libraries by "feature". This answers the |
141 | | -question "what libraries are needed to provide specified features": |
142 | | - |
143 | | -```console |
144 | | -$ dlopen-notes.py -f archive,bpf /usr/lib64/systemd/libsystemd-shared-257.so |
145 | | -# grouped by feature |
146 | | -{ |
147 | | - "bpf": { |
148 | | - "description": "Support firewalling and sandboxing with BPF", |
149 | | - "sonames": { |
150 | | - "libbpf.so.1": "suggested", |
151 | | - "libbpf.so.0": "suggested" |
152 | | - } |
153 | | - }, |
154 | | - "archive": { |
155 | | - "description": "Support for decompressing archive files", |
156 | | - "sonames": { |
157 | | - "libarchive.so.13": "suggested" |
158 | | - } |
159 | | - } |
160 | | -} |
161 | | - |
162 | | -The format that is used when building `deb` packages: |
163 | | -```console |
164 | | -$ dlopen-notes -s /usr/lib64/systemd/libsystemd-shared-257.so |
165 | | -libarchive.so.13 suggested |
166 | | -libbpf.so.0 suggested |
167 | | -libbpf.so.1 suggested |
168 | | -... |
169 | | -``` |
170 | | - |
171 | | -The format that can be useful when building `rpm` packages: |
172 | | -```console |
173 | | -$ dlopen-notes --rpm-requires archive --rpm-recommends bpf /usr/lib64/systemd/libsystemd-shared-257.so |
174 | | -Requires: libarchive.so.13()(64bit) |
175 | | -Recommends: libbpf.so.1()(64bit) |
176 | | -``` |
| 1 | +[This content has moved to the UAPI group website](https://uapi-group.org/specifications/specs/elf_dlopen_metadata/) |
0 commit comments