@@ -52,8 +52,10 @@ 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 tst-dlmem-extfns
+ bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-extfns \
+ tst-dlmem-shm
CPPFLAGS-tst-dlmem-extfns.c += -DBUILDDIR=\"$(objpfx)\"
+CPPFLAGS-tst-dlmem-shm.c += -DBUILDDIR=\"$(objpfx)\"
endif
modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
defaultmod2 errmsg1mod modatexit modcxaatexit \
@@ -110,6 +112,7 @@ $(objpfx)glreflib1.img: $(objpfx)glreflib1.so
cat $^ >>$@
dd if=/dev/urandom bs=512 count=1 >>$@
$(objpfx)tst-dlmem-extfns.out: $(objpfx)glreflib1.so $(objpfx)glreflib1.img
+$(objpfx)tst-dlmem-shm.out: $(objpfx)glreflib1.so
$(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so
LDFLAGS-glreflib3.so = -Wl,-rpath,:
@@ -73,6 +73,10 @@ typedef void *
(dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign,
void *cookie);
+/* Do not replace mapping created by premap callback.
+ dlmem() will then use memcpy(). */
+#define DLMEM_DONTREPLACE 1
+
struct dlmem_args {
/* Optional name to associate with the loaded object. */
const char *soname;
@@ -22,3 +22,5 @@ ref1 (void)
{
return 42;
}
+
+int bar = 35;
new file mode 100644
@@ -0,0 +1,169 @@
+/* Test for dlmem into shm.
+ 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 <support/check.h>
+
+static size_t maplen;
+
+static void *
+premap_dlmem (void *mappref, size_t maplength, size_t mapalign, void *cookie)
+{
+ int fd = * (int *) cookie;
+ int prot = PROT_READ | PROT_WRITE;
+ int err;
+
+ /* See if we support such parameters. */
+ if (mappref || mapalign > 4096)
+ return MAP_FAILED;
+
+ fprintf (stderr, "%s\n", __func__);
+
+ err = ftruncate (fd, maplength);
+ if (err)
+ error (EXIT_FAILURE, 0, "ftruncate() failed");
+ maplen = maplength;
+ return mmap (NULL, maplength, prot, MAP_SHARED | MAP_FILE
+#ifdef MAP_32BIT
+ | MAP_32BIT
+#endif
+ , fd, 0);
+}
+
+#define TEST_FUNCTION do_test
+extern int do_test (void);
+
+int
+do_test (void)
+{
+ void *handle;
+ void *addr;
+ int (*sym) (void); /* We load ref1 from glreflib1.c. */
+ int *bar, *bar2;
+ unsigned char *addr2;
+ Dl_info info;
+ int ret;
+ int fd;
+ int num;
+ off_t len;
+ struct link_map *lm;
+ const char *shm_name = "/tst-dlmem";
+ int shm_fd;
+ struct dlmem_args a;
+
+ shm_fd = memfd_create (shm_name, 0);
+ if (shm_fd == -1)
+ error (EXIT_FAILURE, 0, "shm_open() failed");
+
+ fd = open (BUILDDIR "glreflib1.so", O_RDONLY);
+ if (fd == -1)
+ error (EXIT_FAILURE, 0, "cannot open: glreflib1.so");
+ 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)
+ error (EXIT_FAILURE, 0, "cannot mmap: glreflib1.so");
+ a.soname = "glreflib1.so";
+ a.flags = DLMEM_DONTREPLACE;
+ a.nsid = LM_ID_BASE;
+ a.premap = premap_dlmem;
+ a.cookie = &shm_fd;
+ handle = dlmem (addr, len, RTLD_NOW | RTLD_LOCAL, &a);
+ if (handle == NULL)
+ error (EXIT_FAILURE, 0, "cannot load: glreflib1.so");
+ munmap (addr, len);
+ close (fd);
+ /* Check if premap was called. */
+ TEST_VERIFY (maplen != 0);
+
+ sym = dlsym (handle, "ref1");
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, "dlsym failed");
+
+ memset (&info, 0, sizeof (info));
+ ret = dladdr (sym, &info);
+ if (ret == 0)
+ error (EXIT_FAILURE, 0, "dladdr failed");
+#ifdef MAP_32BIT
+ /* Make sure MAP_32BIT worked. */
+ if ((unsigned long) info.dli_fbase >= 0x100000000)
+ error (EXIT_FAILURE, 0, "premap audit didn't work");
+#endif
+ ret = dlinfo (handle, RTLD_DI_LINKMAP, &lm);
+ if (ret != 0)
+ error (EXIT_FAILURE, 0, "dlinfo 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);
+ printf ("lm->l_addr = %lx\n", lm->l_addr);
+
+ 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");
+
+ num = sym ();
+ if (num != 42)
+ error (EXIT_FAILURE, 0, "bad return from ref1");
+
+ /* Now try symbol duplication. */
+ bar = dlsym (handle, "bar");
+ if (bar == NULL)
+ error (EXIT_FAILURE, 0, "dlsym failed");
+ TEST_COMPARE (*bar, 35);
+ /* write another value */
+#define TEST_BAR_VAL 48
+ *bar = TEST_BAR_VAL;
+
+ /* Create second instance of the solib. */
+ addr2 = mmap (NULL, maplen, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_SHARED, shm_fd, 0);
+ if (addr2 == MAP_FAILED)
+ error (EXIT_FAILURE, 0, "cannot mmap shm\n");
+ /* Find our bar symbol duplicate. */
+ ret = dladdr (bar, &info);
+ if (ret == 0)
+ error (EXIT_FAILURE, 0, "dladdr failed");
+ bar2 = (int *) (addr2 + (info.dli_saddr - info.dli_fbase));
+ /* See if we found the right one. */
+ TEST_COMPARE (*bar2, TEST_BAR_VAL);
+
+ munmap (addr2, maplen);
+ close (shm_fd);
+ dlclose (handle);
+
+ return 0;
+}
+
+
+#include <support/test-driver.c>
@@ -2352,6 +2352,31 @@ _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_mmapcpy (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);
+ assert ((flags & MAP_ANONYMOUS) || fb);
+
+ if (!(flags & MAP_ANONYMOUS) && offset < fb->len)
+ {
+ to_copy = length;
+ if (offset + to_copy > fb->len)
+ to_copy = fb->len - offset;
+ memcpy (addr, fb->buf + offset, to_copy);
+ }
+ /* 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_memremap (void *addr, size_t length, int prot, int flags,
void *arg, off_t offset)
@@ -2360,6 +2385,11 @@ do_memremap (void *addr, size_t length, int prot, int flags,
size_t to_copy = 0;
assert (flags & MAP_FIXED);
+ assert ((flags & MAP_ANONYMOUS) || fb);
+
+ if (flags & MAP_ANONYMOUS)
+ return __mmap (addr, length, prot, flags, -1, 0);
+
if (offset < fb->len)
{
to_copy = length;
@@ -2430,6 +2460,10 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name,
struct r_debug *r = _dl_debug_update (nsid);
bool make_consistent = false;
struct r_file_id id = {};
+ const struct dlmem_fbuf *fb = private;
+ unsigned dlmem_flags = fb->dlm_args ? fb->dlm_args->flags : 0;
+ __typeof (do_mmap) *m_map = (dlmem_flags & DLMEM_DONTREPLACE)
+ ? do_mmapcpy : do_memremap;
assert (nsid >= 0);
assert (nsid < GL(dl_nns));
@@ -2480,7 +2514,7 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name,
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))
+ &errstring, m_map, do_dlmem_premap))
goto lose;
_dl_map_object_2 (l, mode, id, NULL, nsid);
@@ -187,9 +187,9 @@ _dl_map_segments (struct link_map *l, void *fd,
{
/* Map the remaining zero pages in from the zero fill FD. */
caddr_t mapat;
- mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
+ mapat = m_map ((caddr_t) zeropage, zeroend - zeropage,
c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
- -1, 0);
+ NULL, 0);
if (__glibc_unlikely (mapat == MAP_FAILED))
return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL;
}