From 1f49475e3df9db13b4620b8e72fc3cd7d0e686f2 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Sat, 30 Nov 2024 00:30:53 -0600 Subject: [PATCH] util: Add dlfcn helpers Heavily based on systemd: add similar (but simplified) functions to dlopen() a library and load specific symbols from it. This will be useful to allow to load the compression libraries as needed. A few differences from the systemd implementation: 1) It's allowed to link directly to the library and hence bypass the dlopen() + dlsym() 2) The only entrypoint is dlsym_many() which is already declared with the sentinel: it's expected callers will use an x-macro that doesn't allow forgetting the sentinel 3) No support yet for ELF info annotation yet Signed-off-by: Lucas De Marchi Reviewed-by: Emil Velikov Link: https://github.com/kmod-project/kmod/pull/262 --- shared/macro.h | 1 + shared/util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ shared/util.h | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/shared/macro.h b/shared/macro.h index 2def79f2..7b4ea421 100644 --- a/shared/macro.h +++ b/shared/macro.h @@ -43,6 +43,7 @@ #define _must_check_ __attribute__((warn_unused_result)) #define _printf_format_(a, b) __attribute__((format(printf, a, b))) #define _always_inline_ __inline__ __attribute__((always_inline)) +#define _sentinel_ __attribute__((sentinel)) #if defined(__clang_analyzer__) #define _clang_suppress_ __attribute__((suppress)) diff --git a/shared/util.c b/shared/util.c index 81026ca3..9a54c07e 100644 --- a/shared/util.c +++ b/shared/util.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -560,3 +561,46 @@ unsigned long long stat_mstamp(const struct stat *st) return (unsigned long long)st->st_mtime; #endif } + +static int dlsym_manyv(void *dl, va_list ap) +{ + void (**fn)(void); + + while ((fn = va_arg(ap, typeof(fn)))) { + const char *symbol; + + symbol = va_arg(ap, typeof(symbol)); + *fn = dlsym(dl, symbol); + if (!*fn) + return -ENXIO; + } + + return 0; +} + +int dlsym_many(void **dlp, const char *filename, ...) +{ + va_list ap; + void *dl; + int r; + + if (*dlp) + return 0; + + dl = dlopen(filename, RTLD_LAZY); + if (!dl) + return -ENOENT; + + va_start(ap, filename); + r = dlsym_manyv(dl, ap); + va_end(ap); + + if (r < 0) { + dlclose(dl); + return r; + } + + *dlp = dl; + + return 1; +} diff --git a/shared/util.h b/shared/util.h index 7c8bb95b..c6af2e3a 100644 --- a/shared/util.h +++ b/shared/util.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -165,3 +166,37 @@ static inline bool umulsz_overflow(size_t a, size_t b, size_t *res) (x) = NULL; \ x__; \ }) + +/* dlfcn helpers */ +/* ************************************************************************ */ + +/* + * Load many various symbols from @filename. + * @dlp: pointer to the previous results of this call: it's set when it succeeds + * @filename: the library to dlopen() and look for symbols + * @...: or 1 more tuples created by DLSYM_ARG() with ( &var, "symbol name" ). + */ +_sentinel_ int dlsym_many(void **dlp, const char *filename, ...); + +/* + * Helper to create tuples passed as arguments to dlsym_many(). + * @symbol__: symbol to create arguments for. Example: DLSYM_ARG(foo) expands to + * `&sym_foo, "foo"` + */ +#define DLSYM_ARG(symbol__) &sym_##symbol__, STRINGIFY(symbol__), + +/* For symbols being dynamically loaded */ +#define DECLARE_DLSYM(symbol) typeof(symbol) *sym_##symbol = NULL + +/* Pointer indirection to support linking directly */ +#define DECLARE_PTRSYM(symbol) typeof(symbol) *sym_##symbol = symbol + +/* + * Helper defines, to be done locally before including this header to switch between + * implementations + */ +#if defined(DLSYM_LOCALLY_ENABLED) && DLSYM_LOCALLY_ENABLED +#define DECLARE_SYM(sym__) DECLARE_DLSYM(sym__); +#else +#define DECLARE_SYM(sym__) DECLARE_PTRSYM(sym__); +#endif -- 2.47.2