@@ -28,6 +28,7 @@ routines = \
dlclose \
dlerror \
dlinfo \
+ dlmem \
dlmopen \
dlopen \
dlsym \
@@ -51,7 +52,8 @@ endif
ifeq (yes,$(build-shared))
tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
- bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen
+ bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-extfns
+CPPFLAGS-tst-dlmem-extfns.c += -DBUILDDIR=\"$(objpfx)\"
endif
modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
defaultmod2 errmsg1mod modatexit modcxaatexit \
@@ -102,6 +104,12 @@ $(objpfx)glrefmain.out: $(objpfx)glrefmain \
$(objpfx)failtest.out: $(objpfx)failtestmod.so
$(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so
+# Create fancy container file with solib within.
+$(objpfx)glreflib1.img: $(objpfx)glreflib1.so
+ dd if=/dev/urandom bs=512 count=1 >$@
+ cat $^ >>$@
+ dd if=/dev/urandom bs=512 count=1 >>$@
+$(objpfx)tst-dlmem-extfns.out: $(objpfx)glreflib1.so $(objpfx)glreflib1.img
$(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so
LDFLAGS-glreflib3.so = -Wl,-rpath,:
@@ -28,6 +28,9 @@ libc {
dlsym;
dlvsym;
}
+ GLIBC_2.38 {
+ dlmem;
+ }
GLIBC_PRIVATE {
__libc_dlerror_result;
_dlerror_run;
@@ -68,6 +68,28 @@ extern void *dlsym (void *__restrict __handle,
/* Like `dlopen', but request object to be allocated in a new namespace. */
extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL;
+/* Callback for dlmem. */
+typedef void *
+(dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign,
+ void *cookie);
+
+struct dlmem_args {
+ /* Optional name to associate with the loaded object. */
+ const char *soname;
+ /* Namespace where to load the object. */
+ Lmid_t nsid;
+ /* dlmem-specific flags. */
+ unsigned int flags;
+ /* Optional premap callback. */
+ dlmem_premap_t *premap;
+ /* Optional argument for premap callback. */
+ void *cookie;
+};
+
+/* Like `dlmopen', but loads shared object from memory buffer. */
+extern void *dlmem (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args);
+
/* Find the run-time address in the shared object HANDLE refers to
of the symbol called NAME with VERSION. */
extern void *dlvsym (void *__restrict __handle,
new file mode 100644
@@ -0,0 +1,86 @@
+/* Load a shared object from memory.
+ Copyright (C) 1995-2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <shlib-compat.h>
+
+struct _dlmem_args
+{
+ /* The arguments for dlmem_doit. */
+ const unsigned char *buffer;
+ size_t size;
+ int mode;
+ struct dlmem_args *args;
+ /* The return value of dlmem_doit. */
+ void *new;
+ /* Address of the caller. */
+ const void *caller;
+};
+
+static void
+dlmem_doit (void *a)
+{
+ struct _dlmem_args *args = (struct _dlmem_args *) a;
+
+ if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND
+ | RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE
+ | __RTLD_SPROF))
+ _dl_signal_error (EINVAL, NULL, NULL, _("invalid mode parameter"));
+ if ((uintptr_t) args->buffer & (GLRO(dl_pagesize) - 1))
+ _dl_signal_error (EINVAL, NULL, NULL, _("buffer not aligned"));
+
+ args->new = GLRO(dl_mem) (args->buffer, args->size,
+ args->mode | __RTLD_DLOPEN,
+ args->args,
+ args->caller,
+ __libc_argc, __libc_argv, __environ);
+}
+
+
+static void *
+dlmem_implementation (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args, void *dl_caller)
+{
+ struct _dlmem_args args;
+ args.buffer = buffer;
+ args.size = size;
+ args.mode = mode;
+ args.args = dlm_args;
+ args.caller = dl_caller;
+
+ return _dlerror_run (dlmem_doit, &args) ? NULL : args.new;
+}
+
+void *
+___dlmem (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args)
+{
+ return dlmem_implementation (buffer, size, mode, dlm_args,
+ RETURN_ADDRESS (0));
+}
+
+#ifdef SHARED
+versioned_symbol (libc, ___dlmem, dlmem, GLIBC_2_38);
+#else /* !SHARED */
+weak_alias (___dlmem, dlmem)
+static_link_warning (dlmem)
+#endif /* !SHARED */
new file mode 100644
@@ -0,0 +1,175 @@
+/* Test for external functions (fdlopen, dlopen_with_offset4) on top of dlmem.
+ Copyright (C) 2000-2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <link.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <support/check.h>
+
+/* Load the shared library from an open fd. */
+static void *
+fdlopen (int fd, int flags)
+{
+ off_t len;
+ void *addr;
+ void *handle;
+
+ len = lseek (fd, 0, SEEK_END);
+ lseek (fd, 0, SEEK_SET);
+ addr = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ return NULL;
+ handle = dlmem (addr, len, flags, NULL);
+ munmap (addr, len);
+ return handle;
+}
+
+/* Load the shared library from a container file.
+ file - file name.
+ offset - solib offset within a container file.
+ Highly recommended to be page-aligned.
+ length - solib file length (not a container file length).
+ flags - dlopen() flags. */
+void *dlopen_with_offset4 (const char *file, off_t offset, size_t length,
+ int flags)
+{
+ void *addr;
+ void *handle;
+ int fd;
+ off_t pad_size = (offset & (getpagesize () - 1));
+ off_t aligned_offset = offset - pad_size;
+ size_t map_length = length + pad_size;
+
+ fd = open (file, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ addr = mmap (NULL, map_length, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
+ close(fd);
+ if (addr == MAP_FAILED)
+ return NULL;
+ if (pad_size)
+ {
+ /* We need to fix alignment by hands. :-(
+ And for that we need a shared mapping. */
+ void *addr2 = mmap (NULL, length, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (addr2 == MAP_FAILED)
+ {
+ munmap (addr, map_length);
+ return NULL;
+ }
+ memcpy (addr2, addr + pad_size, length);
+ munmap (addr, map_length);
+ addr = addr2;
+ map_length = length;
+ }
+ handle = dlmem (addr, length, flags, NULL);
+ munmap (addr, map_length);
+ return handle;
+}
+
+
+#define TEST_FUNCTION do_test
+extern int do_test (void);
+
+int
+do_test (void)
+{
+ char cmd[256];
+ void *handle;
+ int (*sym) (void); /* We load ref1 from glreflib1.c. */
+ Dl_info info;
+ int rc;
+ int fd;
+ struct stat sb;
+ const unsigned char *unaligned_buf = (const unsigned char *) 1;
+
+ /* First check the reaction to unaligned buf. */
+ handle = dlmem (unaligned_buf, 4096, RTLD_NOW, NULL);
+ TEST_VERIFY (handle == NULL);
+ /* errno is set by dlerror() so needs to print something. */
+ printf ("unaligned buf gives %s\n", dlerror ());
+ TEST_COMPARE (errno, EINVAL);
+
+ fd = open (BUILDDIR "glreflib1.so", O_RDONLY);
+ if (fd == -1)
+ error (EXIT_FAILURE, 0, "cannot open: glreflib1.so");
+ fstat (fd, &sb);
+ handle = fdlopen (fd, RTLD_NOW);
+ close (fd);
+ if (handle == NULL)
+ {
+ printf ("fdlopen failed, %s\n", dlerror ());
+ exit (EXIT_FAILURE);
+ }
+
+ /* Check that the lib is properly mmap()ed, rather than memcpy()ed.
+ This may fail on linux kernels <5.13. */
+ snprintf (cmd, sizeof(cmd), "grep glreflib1.so /proc/%i/maps", getpid());
+ rc = system (cmd);
+ TEST_COMPARE (rc, 0);
+
+ sym = dlsym (handle, "ref1");
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, "dlsym failed");
+
+ dlclose (handle);
+
+ /* Try to load the solib from container, with the worst, unaligned case. */
+ handle = dlopen_with_offset4 (BUILDDIR "glreflib1.img", 512, sb.st_size,
+ RTLD_NOW);
+
+ sym = dlsym (handle, "ref1");
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, "dlsym failed");
+
+ memset (&info, 0, sizeof (info));
+ rc = dladdr (sym, &info);
+ if (rc == 0)
+ error (EXIT_FAILURE, 0, "dladdr failed");
+
+ printf ("info.dli_fname = %p (\"%s\")\n", info.dli_fname, info.dli_fname);
+ printf ("info.dli_fbase = %p\n", info.dli_fbase);
+ printf ("info.dli_sname = %p (\"%s\")\n", info.dli_sname, info.dli_sname);
+ printf ("info.dli_saddr = %p\n", info.dli_saddr);
+
+ if (info.dli_fname == NULL)
+ error (EXIT_FAILURE, 0, "dli_fname is NULL");
+ if (info.dli_fbase == NULL)
+ error (EXIT_FAILURE, 0, "dli_fbase is NULL");
+ if (info.dli_sname == NULL)
+ error (EXIT_FAILURE, 0, "dli_sname is NULL");
+ if (info.dli_saddr == NULL)
+ error (EXIT_FAILURE, 0, "dli_saddr is NULL");
+
+ /* Handle can be closed only after checking info, as some info fields
+ point to memory that is freed by dlclose(). */
+ dlclose (handle);
+ return 0;
+}
+
+
+#include <support/test-driver.c>
@@ -75,6 +75,7 @@ struct filebuf
#include <dl-machine-reject-phdr.h>
#include <dl-sysdep-open.h>
#include <dl-prop.h>
+#include <dl-main.h>
#include <not-cancel.h>
#include <endian.h>
@@ -2351,6 +2352,178 @@ _dl_map_object (struct link_map *loader, const char *name,
return __dl_map_object (loader, name, NULL, type, trace_mode, mode, nsid);
}
+static void *
+do_memremap (void *addr, size_t length, int prot, int flags,
+ void *arg, off_t offset)
+{
+ const struct dlmem_fbuf *fb = arg;
+ size_t to_copy = 0;
+
+ assert (flags & MAP_FIXED);
+ if (offset < fb->len)
+ {
+ to_copy = length;
+ if (offset + to_copy > fb->len)
+ to_copy = fb->len - offset;
+#ifdef MREMAP_DONTUNMAP
+ void *addr2 = __mremap ((void *) (fb->buf + offset), to_copy, to_copy,
+ MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP,
+ addr);
+ /* MREMAP_DONTUNMAP introduced in linux-5.7, but only works for
+ file-based maps since commit a460938 went in 5.13.
+ So have a fall-back. */
+ if (addr2 == MAP_FAILED)
+ memcpy (addr, fb->buf + offset, to_copy);
+#else
+ /* MREMAP_DONTUNMAP is not always available. This is a fall-back. */
+ memcpy (addr, fb->buf + offset, to_copy);
+#endif
+ }
+ /* memset the rest. */
+ if (length > to_copy)
+ memset (addr + to_copy, 0, length - to_copy);
+ if (__mprotect (addr, length, prot) == -1)
+ return MAP_FAILED;
+ return addr;
+}
+
+static void *
+do_dlmem_premap (void *mappref, size_t maplength, size_t mapalign,
+ void *cookie)
+{
+ struct dlmem_fbuf *fb = cookie;
+ void *ret = MAP_FAILED;
+
+ if (fb->dlm_args && fb->dlm_args->premap)
+ ret = fb->dlm_args->premap (mappref, maplength, mapalign,
+ fb->dlm_args->cookie);
+ if (ret == MAP_FAILED)
+ ret = (void *) _dl_map_segment ((ElfW(Addr)) mappref, maplength,
+ mapalign);
+ return ret;
+}
+
+static ssize_t
+do_pread_memcpy (void *arg, void *buf, size_t count, off_t offset)
+{
+ struct dlmem_fbuf *fb = arg;
+ if (offset >= fb->len)
+ return -1;
+ if (offset + count > fb->len)
+ count = fb->len - offset;
+ if (count)
+ memcpy (buf, fb->buf + offset, count);
+ return count;
+}
+
+static struct link_map *
+___dl_map_object_from_mem (struct link_map *loader, const char *name,
+ void *private, int type, int trace_mode,
+ int mode, Lmid_t nsid, struct filebuf *fbp)
+{
+ struct link_map *l;
+ int err;
+ char *realname;
+ /* Initialize to keep the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+ struct r_debug *r = _dl_debug_update (nsid);
+ bool make_consistent = false;
+ struct r_file_id id = {};
+
+ assert (nsid >= 0);
+ assert (nsid < GL(dl_nns));
+
+ if (name && *name)
+ {
+ /* Look for this name among those already loaded. */
+ l = _dl_check_loaded (name, nsid);
+ if (l)
+ return l;
+ }
+
+ /* Will be true if we found a DSO which is of the other ELF class. */
+ bool found_other_class = false;
+
+ err = do_open_verify (name, private, fbp,
+ loader ?: GL(dl_ns)[nsid]._ns_loaded,
+ &found_other_class, false, do_pread_memcpy);
+ if (err)
+ return NULL;
+
+ /* In case the LOADER information has only been provided to get to
+ the appropriate RUNPATH/RPATH information we do not need it
+ anymore. */
+ if (mode & __RTLD_CALLMAP)
+ loader = NULL;
+
+ if (mode & RTLD_NOLOAD)
+ {
+ /* We are not supposed to load the object unless it is already
+ loaded. So return now. */
+ return NULL;
+ }
+
+ /* Print debugging message. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("dlmem [%lu]; generating link map\n", nsid);
+
+ /* _dl_new_object() treats "" separately and doesn't free it. */
+ realname = *name ? __strdup (name) : (char *) "";
+ /* Enter the new object in the list of loaded objects. */
+ l = _dl_new_object (realname, name, type, loader, mode, nsid);
+ if (__glibc_unlikely (l == NULL))
+ {
+ errstring = N_("cannot create shared object descriptor");
+ goto lose_errno;
+ }
+
+ void *stack_end = __libc_stack_end;
+ if (_dl_map_object_1 (l, private, fbp, mode, loader, &stack_end, &errval,
+ &errstring, do_memremap, do_dlmem_premap))
+ goto lose;
+
+ _dl_map_object_2 (l, mode, id, NULL, nsid);
+ return l;
+
+lose_errno:
+ errval = errno;
+lose:
+ if (l != NULL && l->l_map_start != 0)
+ _dl_unmap_segments (l);
+ if (l != NULL && l->l_origin != (char *) -1l)
+ free ((char *) l->l_origin);
+ if (l != NULL && !l->l_libname->dont_free)
+ free (l->l_libname);
+ if (l != NULL && l->l_phdr_allocated)
+ free ((void *) l->l_phdr);
+ free (l);
+
+ if (make_consistent && r != NULL)
+ {
+ r->r_state = RT_CONSISTENT;
+ _dl_debug_state ();
+ LIBC_PROBE (map_failed, 2, nsid, r);
+ }
+
+ _dl_signal_error (errval, NULL, NULL, errstring);
+ return NULL;
+}
+
+struct link_map *
+__dl_map_object_from_mem (struct link_map *loader, const char *name,
+ void *private, int type, int trace_mode,
+ int mode, Lmid_t nsid)
+{
+ struct link_map *ret;
+ struct filebuf fb = {};
+
+ ret = ___dl_map_object_from_mem (loader, name, private, type, trace_mode,
+ mode, nsid, &fb);
+ filebuf_done (&fb);
+ return ret;
+}
+
struct add_path_state
{
bool counting;
@@ -106,6 +106,9 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
- c->mapoff);
}
+static void *
+do_mmap (void *addr, size_t length, int prot, int flags,
+ void *arg, off_t offset);
/* This is a subroutine of _dl_map_object_from_fd. It is responsible
for filling in several fields in *L: l_map_start, l_map_end, l_addr,
@@ -104,6 +104,13 @@ struct dl_main_state
bool version_info;
};
+struct dlmem_fbuf
+{
+ ssize_t len;
+ const unsigned char *buf;
+ struct dlmem_args *dlm_args;
+};
+
/* Open the shared object NAME and map in its segments.
LOADER's DT_RPATH is used in searching for NAME.
If the object is already opened, returns its existing map. */
@@ -112,6 +119,11 @@ __dl_map_object (struct link_map *loader,
const char *name, void *private,
int type, int trace_mode, int mode,
Lmid_t nsid) attribute_hidden;
+extern struct link_map *
+__dl_map_object_from_mem (struct link_map *loader,
+ const char *name, void *private,
+ int type, int trace_mode, int mode,
+ Lmid_t nsid) attribute_hidden;
/* Helper function to invoke _dl_init_paths with the right arguments
from *STATE. */
@@ -122,7 +122,10 @@ _dl_new_object (char *realname, const char *libname, int type,
#endif
new->l_name = realname;
else
- new->l_name = (char *) newname->name + libname_len - 1;
+ /* When realname="", it is not allocated and points to the constant
+ string. Constness is dropped by an explicit cast. :(
+ So strdup() it here. */
+ new->l_name = __strdup ("");
new->l_type = type;
/* If we set the bit now since we know it is never used we avoid
@@ -957,6 +957,19 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
__dl_map_object);
}
+void *
+_dl_mem (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args, const void *caller_dlopen,
+ int argc, char *argv[], char *env[])
+{
+ struct dlmem_fbuf fb = { .buf = buffer, .len = size, .dlm_args = dlm_args };
+ Lmid_t nsid = dlm_args ? dlm_args->nsid : LM_ID_BASE;
+ const char *file = (dlm_args && dlm_args->soname) ? dlm_args->soname : "";
+
+ return do_dl_open (file, &fb, mode, caller_dlopen, nsid, argc, argv, env,
+ __dl_map_object_from_mem);
+}
+
void
_dl_show_scope (struct link_map *l, int from)
{
@@ -367,6 +367,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_mcount = _dl_mcount,
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
._dl_open = _dl_open,
+ ._dl_mem = _dl_mem,
._dl_close = _dl_close,
._dl_catch_error = _dl_catch_error,
._dl_error_free = _dl_error_free,
@@ -209,6 +209,7 @@ This function is a GNU extension.
@c dladdr1
@c dlclose
@c dlerror
+@c dlmem
@c dlmopen
@c dlopen
@c dlsym
@@ -664,6 +664,9 @@ struct rtld_global_ro
struct link_map *);
void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen,
Lmid_t nsid, int argc, char *argv[], char *env[]);
+ void *(*_dl_mem) (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args, const void *caller_dlopen,
+ int argc, char *argv[], char *env[]);
void (*_dl_close) (void *map);
/* libdl in a secondary namespace (after dlopen) must use
_dl_catch_error from the main namespace, so it has to be
@@ -1235,6 +1238,12 @@ extern void *_dl_open (const char *name, int mode, const void *caller,
Lmid_t nsid, int argc, char *argv[], char *env[])
attribute_hidden;
+/* Open shared object from memory buffer. */
+extern void *_dl_mem (const unsigned char *buffer, size_t size, int mode,
+ struct dlmem_args *dlm_args, const void *caller,
+ int argc, char *argv[], char *env[])
+ attribute_hidden;
+
/* Free or queue for freeing scope OLD. If other threads might be
in the middle of _dl_fixup, _dl_profile_fixup or dl*sym using the
old scope, OLD can't be freed until no thread is using it. */
@@ -2326,6 +2326,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2665,3 +2665,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2774,6 +2774,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2426,3 +2426,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -546,6 +546,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -543,6 +543,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
@@ -2702,3 +2702,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2651,6 +2651,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2835,6 +2835,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2600,6 +2600,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2186,3 +2186,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -547,6 +547,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
@@ -2778,6 +2778,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2751,3 +2751,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2748,3 +2748,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2743,6 +2743,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2741,6 +2741,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2749,6 +2749,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2651,6 +2651,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2790,3 +2790,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2172,3 +2172,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2817,6 +2817,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2850,6 +2850,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2571,6 +2571,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2885,3 +2885,4 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2428,3 +2428,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2628,3 +2628,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
@@ -2815,6 +2815,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2608,6 +2608,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2658,6 +2658,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2655,6 +2655,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2810,6 +2810,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F
GLIBC_2.38 __nldbl___isoc23_vswscanf F
GLIBC_2.38 __nldbl___isoc23_vwscanf F
GLIBC_2.38 __nldbl___isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
@@ -2623,6 +2623,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2574,6 +2574,7 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -2680,3 +2680,4 @@ GLIBC_2.38 __isoc23_wcstoull F
GLIBC_2.38 __isoc23_wcstoull_l F
GLIBC_2.38 __isoc23_wcstoumax F
GLIBC_2.38 __isoc23_wscanf F
+GLIBC_2.38 dlmem F