Skip to content

Commit 8f8fc35

Browse files
committed
Record dynamic dependencies in .note.dlopen elf section
The data can be used with `dlopen-notes`. The raw date can be viewed with `objdump -j .note.dlopen -s libSDL3.so.0`
1 parent 6c61a94 commit 8f8fc35

26 files changed

+417
-90
lines changed

CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ dep_option(SDL_ARMNEON "Use NEON assembly routines" ON "SDL_ASSEMBLY
320320
dep_option(SDL_LSX "Use LSX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_LOONGARCH64" OFF)
321321
dep_option(SDL_LASX "Use LASX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_LOONGARCH64" OFF)
322322

323+
dep_option(SDL_DLOPEN_NOTES "Record dlopen dependencies in .note.dlopen section" TRUE UNIX_SYS OFF)
323324
set_option(SDL_LIBC "Use the system C library" ${SDL_LIBC_DEFAULT})
324325
set_option(SDL_SYSTEM_ICONV "Use iconv() from system-installed libraries" ${SDL_SYSTEM_ICONV_DEFAULT})
325326
set_option(SDL_LIBICONV "Prefer iconv() from libiconv, if available, over libc version" OFF)
@@ -1559,6 +1560,25 @@ elseif(EMSCRIPTEN)
15591560
CheckLibUnwind()
15601561

15611562
elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
1563+
1564+
if(SDL_DLOPEN_NOTES)
1565+
set(CHECK_ELF_DLNOTES_SRC [==[
1566+
#ifndef __ELF__
1567+
ELF DL notes is only supported on ELF platforms
1568+
#endif
1569+
__attribute__ ((used,aligned(4),section(".note.dlopen"))) static const struct {
1570+
struct { int a; int b; int c; } hdr; char name[4]; __attribute__((aligned(4))) char json[24];
1571+
} dlnote = { { 4, 0x407c0c0aU, 16 }, "FDO", "[\\"a\\":{\\"a\\":\\"1\\",\\"b\\":\\"2\\"}]" };
1572+
int main(int argc, char *argv[]) {
1573+
return argc + dlnote.hdr.a;
1574+
}
1575+
]==])
1576+
check_c_source_compiles("${CHECK_ELF_DLNOTES_SRC}" COMPILER_SUPPORTS_ELFNOTES)
1577+
if(COMPILER_SUPPORTS_ELFNOTES)
1578+
set(HAVE_DLOPEN_NOTES TRUE)
1579+
endif()
1580+
endif()
1581+
15621582
if(SDL_AUDIO)
15631583
if(NETBSD)
15641584
set(SDL_AUDIO_DRIVER_NETBSD 1)

docs/README-linux.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev li
2626
Fedora 35, all available features enabled:
2727

2828
sudo yum install gcc git-core make cmake \
29-
alsa-lib-devel pulseaudio-libs-devel nas-devel pipewire-devel \
29+
alsa-lib-devel pulseaudio-libs-devel pipewire-devel \
3030
libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \
3131
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \
3232
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \

include/build_config/SDL_build_config.h.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@
231231
#cmakedefine HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR 1
232232
#cmakedefine HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1
233233

234+
#cmakedefine HAVE_DLOPEN_NOTES 1
235+
234236
/* SDL internal assertion support */
235237
#cmakedefine SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED 1
236238
#ifdef SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED

src/SDL_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "SDL_build_config.h"
6464

6565
#include "dynapi/SDL_dynapi.h"
66+
#include "dynapi/SDL_dynapi_dlopennote.h"
6667

6768
#if SDL_DYNAMIC_API
6869
#include "dynapi/SDL_dynapi_overrides.h"

src/audio/aaudio/SDL_aaudio.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ struct SDL_PrivateAudioData
5353

5454
#define LIB_AAUDIO_SO "libaaudio.so"
5555

56+
SDL_ELF_NOTE_DLOPEN(,
57+
"audio-aaudio",
58+
"Support for audio through AAudio",
59+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
60+
LIB_AAUDIO_SO
61+
);
62+
5663
typedef struct AAUDIO_Data
5764
{
5865
SDL_SharedObject *handle;
@@ -308,8 +315,8 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
308315
ctx.AAudioStreamBuilder_setFormat(builder, format);
309316
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
310317
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
311-
312-
// If no specific buffer size has been requested, the device will pick the optimal
318+
319+
// If no specific buffer size has been requested, the device will pick the optimal
313320
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
314321
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
315322
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size

src/audio/alsa/SDL_alsa_audio.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ static bool load_alsa_syms(void)
207207

208208
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
209209

210+
SDL_ELF_NOTE_DLOPEN(
211+
"audio-libalsa",
212+
"Support for audio through libalsa",
213+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
214+
SDL_AUDIO_DRIVER_ALSA_DYNAMIC
215+
);
216+
210217
static void UnloadALSALibrary(void)
211218
{
212219
if (alsa_handle) {

src/audio/jack/SDL_jackaudio.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ static bool load_jack_syms(void);
5050

5151
#ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
5252

53+
SDL_ELF_NOTE_DLOPEN(
54+
"audio-libjack",
55+
"Support for audio through libjack",
56+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
57+
SDL_AUDIO_DRIVER_JACK_DYNAMIC
58+
);
59+
5360
static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
5461
static SDL_SharedObject *jack_handle = NULL;
5562

src/audio/pipewire/SDL_pipewire.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *,
9393

9494
#ifdef SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
9595

96+
SDL_ELF_NOTE_DLOPEN(
97+
"audio-libpipewire",
98+
"Support for audio through libpipewire",
99+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
100+
SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
101+
);
102+
96103
static const char *pipewire_library = SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC;
97104
static SDL_SharedObject *pipewire_handle = NULL;
98105

src/audio/pulseaudio/SDL_pulseaudio.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ static bool load_pulseaudio_syms(void);
133133

134134
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
135135

136+
SDL_ELF_NOTE_DLOPEN(
137+
"audio-libpulseaudio",
138+
"Support for audio through libpulseaudio",
139+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
140+
SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
141+
);
142+
136143
static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
137144
static SDL_SharedObject *pulseaudio_handle = NULL;
138145

src/audio/sndio/SDL_sndioaudio.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ static bool load_sndio_syms(void)
108108

109109
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
110110

111+
SDL_ELF_NOTE_DLOPEN(
112+
"audio-libsndio",
113+
"Support for audio through libsndio",
114+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
115+
SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
116+
);
117+
111118
static void UnloadSNDIOLibrary(void)
112119
{
113120
if (sndio_handle) {

src/camera/pipewire/SDL_camera_pipewire.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *,
109109

110110
#ifdef SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC
111111

112+
SDL_ELF_NOTE_DLOPEN(
113+
"camera-libpipewire",
114+
"Support for camera through libalsa",
115+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
116+
SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC
117+
);
118+
112119
static const char *pipewire_library = SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC;
113120
static SDL_SharedObject *pipewire_handle = NULL;
114121

src/core/linux/SDL_dbus.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,20 @@
2424

2525
#ifdef SDL_USE_LIBDBUS
2626
// we never link directly to libdbus.
27-
static const char *dbus_library = "libdbus-1.so.3";
27+
#define SDL_DRIVER_DBUS_DYNAMIC "libdbus-1.so.3"
28+
static const char *dbus_library = SDL_DRIVER_DBUS_DYNAMIC;
2829
static SDL_SharedObject *dbus_handle = NULL;
2930
static char *inhibit_handle = NULL;
3031
static unsigned int screensaver_cookie = 0;
3132
static SDL_DBusContext dbus;
3233

34+
SDL_ELF_NOTE_DLOPEN(
35+
"core-libdbus",
36+
"Support for DBus RPC",
37+
SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED,
38+
SDL_DRIVER_DBUS_DYNAMIC
39+
);
40+
3341
static bool LoadDBUSSyms(void)
3442
{
3543
#define SDL_DBUS_SYM2_OPTIONAL(TYPE, x, y) \

src/core/linux/SDL_udev.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@
3838

3939
static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
4040

41+
#ifdef SDL_UDEV_DYNAMIC
42+
43+
SDL_ELF_NOTE_DLOPEN(
44+
"events-udev",
45+
"Support for events through libudev",
46+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
47+
SDL_UDEV_DYNAMIC
48+
);
49+
50+
#endif
51+
4152
static SDL_UDEV_PrivateData *_this = NULL;
4253

4354
static bool SDL_UDEV_load_sym(const char *fn, void **addr);

src/dynapi/SDL_dynapi_dlopennote.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Simple DirectMedia Layer
3+
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
4+
5+
This software is provided 'as-is', without any express or implied
6+
warranty. In no event will the authors be held liable for any damages
7+
arising from the use of this software.
8+
9+
Permission is granted to anyone to use this software for any purpose,
10+
including commercial applications, and to alter it and redistribute it
11+
freely, subject to the following restrictions:
12+
13+
1. The origin of this software must not be misrepresented; you must not
14+
claim that you wrote the original software. If you use this software
15+
in a product, an acknowledgment in the product documentation would be
16+
appreciated but is not required.
17+
2. Altered source versions must be plainly marked as such, and must not be
18+
misrepresented as being the original software.
19+
3. This notice may not be removed or altered from any source distribution.
20+
*/
21+
22+
#ifndef SDL_dynapi_dlopennote_h
23+
#define SDL_dynapi_dlopennote_h
24+
25+
#define SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED "required"
26+
#define SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended"
27+
#define SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED "suggested"
28+
29+
#if defined(__ELF__) && defined(HAVE_DLOPEN_NOTES)
30+
31+
#define SDL_ELF_NOTE_DLOPEN_VENDOR "FDO"
32+
#define SDL_ELF_NOTE_DLOPEN_TYPE 0x407c0c0aU
33+
34+
#define SDL_ELF_NOTE_INTERNAL2(json, variable_name) \
35+
__attribute__((aligned(4), used, section(".note.dlopen"))) \
36+
static const struct { \
37+
struct { \
38+
Uint32 n_namesz; \
39+
Uint32 n_descsz; \
40+
Uint32 n_type; \
41+
} nhdr; \
42+
char name[4]; \
43+
__attribute__((aligned(4))) char dlopen_json[sizeof(json)]; \
44+
} variable_name = { \
45+
{ \
46+
sizeof(SDL_ELF_NOTE_DLOPEN_VENDOR), \
47+
sizeof(json), \
48+
SDL_ELF_NOTE_DLOPEN_TYPE \
49+
}, \
50+
SDL_ELF_NOTE_DLOPEN_VENDOR, \
51+
json \
52+
}
53+
54+
#define SDL_ELF_NOTE_INTERNAL(json, variable_name) \
55+
SDL_ELF_NOTE_INTERNAL2(json, variable_name)
56+
57+
#define SDL_SONAME_ARRAY1(N1) "[\"" N1 "\"]"
58+
#define SDL_SONAME_ARRAY2(N1,N2) "[\"" N1 "\",\"" N2 "\"]"
59+
#define SDL_SONAME_ARRAY3(N1,N2,N3) "[\"" N1 "\",\"" N2 "\",\"" N3 "\"]"
60+
#define SDL_SONAME_ARRAY4(N1,N2,N3,N4) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\"]"
61+
#define SDL_SONAME_ARRAY5(N1,N2,N3,N4,N5) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\"]"
62+
#define SDL_SONAME_ARRAY6(N1,N2,N3,N4,N5,N6) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\"]"
63+
#define SDL_SONAME_ARRAY7(N1,N2,N3,N4,N5,N6,N7) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\"]"
64+
#define SDL_SONAME_ARRAY8(N1,N2,N3,N4,N5,N6,N7,N8) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\",\"" N8 "\"]"
65+
#define SDL_SONAME_ARRAY_GET(N1,N2,N3,N4,N5,N6,N7,N8,NAME,...) NAME
66+
#define SDL_SONAME_ARRAY(...) \
67+
SDL_SONAME_ARRAY_GET(__VA_ARGS__, \
68+
SDL_SONAME_ARRAY8, \
69+
SDL_SONAME_ARRAY7, \
70+
SDL_SONAME_ARRAY6, \
71+
SDL_SONAME_ARRAY5, \
72+
SDL_SONAME_ARRAY4, \
73+
SDL_SONAME_ARRAY3, \
74+
SDL_SONAME_ARRAY2, \
75+
SDL_SONAME_ARRAY1 \
76+
)(__VA_ARGS__)
77+
78+
// Create "unique" variable name using __LINE__,
79+
// so creating elf notes on the same line is not supported
80+
#define SDL_ELF_NOTE_JOIN2(A,B) A##B
81+
#define SDL_ELF_NOTE_JOIN(A,B) SDL_ELF_NOTE_JOIN2(A,B)
82+
#define SDL_ELF_NOTE_UNIQUE_NAME SDL_ELF_NOTE_JOIN(s_dlopen_note_, __LINE__)
83+
84+
#define SDL_ELF_NOTE_DLOPEN(feature, description, priority, ...) \
85+
SDL_ELF_NOTE_INTERNAL( \
86+
"[{\"feature\":\"" feature \
87+
"\",\"description\":\"" description \
88+
"\",\"priority\":\"" priority \
89+
"\",\"soname\":" SDL_SONAME_ARRAY(__VA_ARGS__) "}]", \
90+
SDL_ELF_NOTE_UNIQUE_NAME)
91+
92+
#else
93+
94+
#define SDL_ELF_NOTE_DLOPEN(...)
95+
96+
#endif
97+
98+
#endif

src/hidapi/SDL_hidapi.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040

4141
#ifndef SDL_HIDAPI_DISABLED
4242

43+
#ifdef SDL_LIBUSB_DYNAMIC
44+
SDL_ELF_NOTE_DLOPEN(
45+
"hidabi-libusb",
46+
"Support for joysticks through libusb",
47+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
48+
SDL_LIBUSB_DYNAMIC
49+
);
50+
#endif
51+
4352
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
4453
#include "../core/windows/SDL_windows.h"
4554
#endif

src/io/io_uring/SDL_asyncio_liburing.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,17 @@ static bool (*AsyncIOFromFile)(const char *file, const char *mode, SDL_AsyncIO *
4444
// we never link directly to liburing.
4545
// (this says "-ffi" which sounds like a scripting language binding thing, but the non-ffi version
4646
// is static-inline code we can't lookup with dlsym. This is by design.)
47-
static const char *liburing_library = "liburing-ffi.so.2";
47+
#define SDL_DRIVER_LIBURING_DYNAMIC "liburing-ffi.so.2"
48+
static const char *liburing_library = SDL_DRIVER_LIBURING_DYNAMIC;
4849
static void *liburing_handle = NULL;
4950

51+
SDL_ELF_NOTE_DLOPEN(
52+
"io-io_uring",
53+
"Support for async IO through liburing",
54+
SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED,
55+
SDL_DRIVER_LIBURING_DYNAMIC
56+
);
57+
5058
#define SDL_LIBURING_FUNCS \
5159
SDL_LIBURING_FUNC(int, io_uring_queue_init, (unsigned entries, struct io_uring *ring, unsigned flags)) \
5260
SDL_LIBURING_FUNC(struct io_uring_probe *,io_uring_get_probe,(void)) \

src/storage/steam/SDL_steamstorage.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@
2323

2424
#include "../SDL_sysstorage.h"
2525

26+
#if defined(_WIN64)
27+
#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api64.dll"
28+
#elif defined(_WIN32)
29+
#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api.dll"
30+
#elif defined(__APPLE__)
31+
#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.dylib"
32+
#else
33+
#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.so"
34+
#endif
35+
36+
SDL_ELF_NOTE_DLOPEN(
37+
"storage-steam",
38+
"Support for Steam storage",
39+
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
40+
SDL_DRIVER_STEAMAPI_DYNAMIC
41+
);
42+
2643
// !!! FIXME: Async API can use SteamRemoteStorage_ReadFileAsync
2744
// !!! FIXME: Async API can use SteamRemoteStorage_WriteFileAsync
2845

@@ -154,17 +171,7 @@ static SDL_Storage *STEAM_User_Create(const char *org, const char *app, SDL_Prop
154171
return NULL;
155172
}
156173

157-
steam->libsteam_api = SDL_LoadObject(
158-
#if defined(_WIN64)
159-
"steam_api64.dll"
160-
#elif defined(_WIN32)
161-
"steam_api.dll"
162-
#elif defined(__APPLE__)
163-
"libsteam_api.dylib"
164-
#else
165-
"libsteam_api.so"
166-
#endif
167-
);
174+
steam->libsteam_api = SDL_LoadObject(SDL_DRIVER_STEAMAPI_DYNAMIC);
168175
if (steam->libsteam_api == NULL) {
169176
SDL_free(steam);
170177
return NULL;

0 commit comments

Comments
 (0)