aboutsummaryrefslogtreecommitdiff
path: root/dlfcn
diff options
context:
space:
mode:
Diffstat (limited to 'dlfcn')
-rw-r--r--dlfcn/Makefile18
-rw-r--r--dlfcn/Versions3
-rw-r--r--dlfcn/dladdr.c21
-rw-r--r--dlfcn/dladdr1.c21
-rw-r--r--dlfcn/dlclose.c24
-rw-r--r--dlfcn/dlerror.c52
-rw-r--r--dlfcn/dlinfo.c28
-rw-r--r--dlfcn/dlmopen.c39
-rw-r--r--dlfcn/dlopen.c48
-rw-r--r--dlfcn/dlopenold.c3
-rw-r--r--dlfcn/dlsym.c23
-rw-r--r--dlfcn/dlvsym.c25
-rw-r--r--dlfcn/modstatic2.c228
-rw-r--r--dlfcn/sdladdr.c1
-rw-r--r--dlfcn/sdladdr1.c1
-rw-r--r--dlfcn/sdlclose.c1
-rw-r--r--dlfcn/sdlerror.c1
-rw-r--r--dlfcn/sdlinfo.c1
-rw-r--r--dlfcn/sdlmopen.c1
-rw-r--r--dlfcn/sdlopen.c1
-rw-r--r--dlfcn/sdlsym.c1
-rw-r--r--dlfcn/sdlvsym.c1
-rw-r--r--dlfcn/tststatic2.c166
23 files changed, 674 insertions, 34 deletions
diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index 4330a8a..ed20ae5 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -21,9 +21,11 @@ headers := bits/dlfcn.h dlfcn.h
extra-libs := libdl
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
dlmopen
+routines := $(patsubst %,s%,$(libdl-routines))
+elide-routines.os := $(routines)
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
- modcxaatexit.c modstatic.c \
+ modcxaatexit.c modstatic.c modstatic2.c \
bug-dlsym1-lib1.c bug-dlsym1-lib2.c
extra-libs-others := libdl
@@ -51,10 +53,11 @@ glreflib2.so-no-z-defs = yes
errmsg1mod.so-no-z-defs = yes
ifeq (yesyesyes,$(build-static)$(build-shared)$(elf))
-tests += tststatic
-tests-static += tststatic
-modules-names += modstatic
+tests += tststatic tststatic2
+tests-static += tststatic tststatic2
+modules-names += modstatic modstatic2
tststatic-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic2-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
endif
extra-objs += $(modules-names:=.os)
@@ -106,7 +109,12 @@ $(objpfx)modatexit.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a
$(objpfx)tststatic: $(objpfx)libdl.a
$(objpfx)tststatic.out: $(objpfx)tststatic $(objpfx)modstatic.so
-$(objpfx)modstatic.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a
+$(objpfx)tststatic2: $(objpfx)libdl.a
+$(objpfx)tststatic2.out: $(objpfx)tststatic2 $(objpfx)modstatic.so \
+ $(objpfx)modstatic2.so
+
+$(objpfx)modstatic2.so: $(libdl) $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
$(objpfx)bug-dlopen1: $(libdl)
diff --git a/dlfcn/Versions b/dlfcn/Versions
index 6a41c23..97902f0 100644
--- a/dlfcn/Versions
+++ b/dlfcn/Versions
@@ -11,4 +11,7 @@ libdl {
GLIBC_2.3.4 {
dlmopen;
}
+ GLIBC_PRIVATE {
+ _dlfcn_hook;
+ }
}
diff --git a/dlfcn/dladdr.c b/dlfcn/dladdr.c
index b5490e5..d0462b9 100644
--- a/dlfcn/dladdr.c
+++ b/dlfcn/dladdr.c
@@ -1,5 +1,6 @@
/* Locate the shared object symbol nearest a given address.
- Copyright (C) 1996, 1997, 1998, 1999, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004
+ 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
@@ -19,8 +20,26 @@
#include <dlfcn.h>
+#if !defined SHARED && defined IS_IN_libdl
+
int
dladdr (const void *address, Dl_info *info)
{
+ return __dladdr (address, info);
+}
+
+#else
+
+int
+__dladdr (const void *address, Dl_info *info)
+{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dladdr (address, info);
+# endif
return _dl_addr (address, info, NULL, NULL);
}
+# ifdef SHARED
+strong_alias (__dladdr, dladdr)
+# endif
+#endif
diff --git a/dlfcn/dladdr1.c b/dlfcn/dladdr1.c
index 51b53b5..0f2b603 100644
--- a/dlfcn/dladdr1.c
+++ b/dlfcn/dladdr1.c
@@ -1,5 +1,5 @@
/* Locate the shared object symbol nearest a given address.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004 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
@@ -19,9 +19,24 @@
#include <dlfcn.h>
+#if !defined SHARED && defined IS_IN_libdl
+
int
dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
{
+ return __dladdr1 (address, info, extra, flags);
+}
+
+#else
+
+int
+__dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
+{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dladdr1 (address, info, extra, flags);
+# endif
+
switch (flags)
{
default: /* Make this an error? */
@@ -33,3 +48,7 @@ dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
return _dl_addr (address, info, (struct link_map **) extra, NULL);
}
}
+# ifdef SHARED
+strong_alias (__dladdr1, dladdr1)
+# endif
+#endif
diff --git a/dlfcn/dlclose.c b/dlfcn/dlclose.c
index 046e6d4..3ddedcf 100644
--- a/dlfcn/dlclose.c
+++ b/dlfcn/dlclose.c
@@ -1,5 +1,6 @@
/* Close a handle opened by `dlopen'.
- Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2004
+ 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
@@ -19,6 +20,16 @@
#include <dlfcn.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+int
+dlclose (void *handle)
+{
+ return __dlclose (handle);
+}
+
+#else
+
static void
dlclose_doit (void *handle)
{
@@ -26,7 +37,16 @@ dlclose_doit (void *handle)
}
int
-dlclose (void *handle)
+__dlclose (void *handle)
{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlclose (handle);
+# endif
+
return _dlerror_run (dlclose_doit, handle) ? -1 : 0;
}
+# ifdef SHARED
+strong_alias (__dlclose, dlclose)
+# endif
+#endif
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 1cde04b..8789f4f 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -25,6 +25,16 @@
#include <bits/libc-lock.h>
#include <ldsodefs.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+char *
+dlerror (void)
+{
+ return __dlerror ();
+}
+
+#else
+
/* Type for storing results of dynamic loading actions. */
struct dl_action_result
{
@@ -46,11 +56,16 @@ static void free_key_mem (void *mem);
char *
-dlerror (void)
+__dlerror (void)
{
char *buf = NULL;
struct dl_action_result *result;
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlerror ();
+# endif
+
/* If we have not yet initialized the buffer do it now. */
__libc_once (once, init);
@@ -99,6 +114,9 @@ dlerror (void)
return buf;
}
+# ifdef SHARED
+strong_alias (__dlerror, dlerror)
+# endif
int
internal_function
@@ -185,3 +203,35 @@ free_key_mem (void *mem)
free (mem);
__libc_setspecific (key, NULL);
}
+
+# ifdef SHARED
+
+struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+libdl_hidden_data_def (_dlfcn_hook)
+
+# else
+
+static struct dlfcn_hook _dlfcn_hooks =
+ {
+ .dlopen = __dlopen,
+ .dlclose = __dlclose,
+ .dlsym = __dlsym,
+ .dlvsym = __dlvsym,
+ .dlerror = __dlerror,
+ .dladdr = __dladdr,
+ .dladdr1 = __dladdr1,
+ .dlinfo = __dlinfo,
+ .dlmopen = __dlmopen
+ };
+
+void
+__libc_register_dlfcn_hook (struct link_map *map)
+{
+ struct dlfcn_hook **hook;
+
+ hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
+ if (hook != NULL)
+ *hook = &_dlfcn_hooks;
+}
+# endif
+#endif
diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
index d54a132..44af55a 100644
--- a/dlfcn/dlinfo.c
+++ b/dlfcn/dlinfo.c
@@ -22,6 +22,16 @@
#include <ldsodefs.h>
#include <libintl.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+int
+dlinfo (void *handle, int request, void *arg)
+{
+ return __dlinfo (handle, request, arg, RETURN_ADDRESS (0));
+}
+
+#else
+
struct dlinfo_args
{
ElfW(Addr) caller;
@@ -36,7 +46,7 @@ dlinfo_doit (void *argsblock)
struct dlinfo_args *const args = argsblock;
struct link_map *l = args->handle;
-#if 0
+# if 0
if (args->handle == RTLD_SELF)
{
Lmid_t nsid;
@@ -53,7 +63,7 @@ dlinfo_doit (void *argsblock)
GLRO(dl_signal_error) (0, NULL, NULL, N_("\
RTLD_SELF used in code not dynamically loaded"));
}
-#endif
+# endif
switch (args->request)
{
@@ -84,9 +94,19 @@ RTLD_SELF used in code not dynamically loaded"));
}
int
-dlinfo (void *handle, int request, void *arg)
+__dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
{
- struct dlinfo_args args = { (ElfW(Addr)) RETURN_ADDRESS (0),
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlinfo (handle, request, arg,
+ DL_CALLER);
+# endif
+
+ struct dlinfo_args args = { (ElfW(Addr)) DL_CALLER,
handle, request, arg };
return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0;
}
+# ifdef SHARED
+strong_alias (__dlinfo, dlinfo)
+# endif
+#endif
diff --git a/dlfcn/dlmopen.c b/dlfcn/dlmopen.c
index fb2a50b..5fd6543 100644
--- a/dlfcn/dlmopen.c
+++ b/dlfcn/dlmopen.c
@@ -23,6 +23,17 @@
#include <stddef.h>
#include <ldsodefs.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlmopen (Lmid_t nsid, const char *file, int mode)
+{
+ return __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
+}
+static_link_warning (dlmopen)
+
+#else
+
struct dlmopen_args
{
/* Namespace ID. */
@@ -43,11 +54,11 @@ dlmopen_doit (void *a)
/* Non-shared code has no support for multiple namespaces. */
if (args->nsid != LM_ID_BASE)
-#ifdef SHARED
+# ifdef SHARED
/* If trying to open the link map for the main executable the namespace
must be the main one. */
if (args->file == NULL)
-#endif
+# endif
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
@@ -56,14 +67,32 @@ dlmopen_doit (void *a)
void *
-dlmopen (Lmid_t nsid, const char *file, int mode)
+__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
+# endif
+
struct dlmopen_args args;
args.nsid = nsid;
args.file = file;
args.mode = mode;
- args.caller = RETURN_ADDRESS (0);
+ args.caller = DL_CALLER;
+# ifdef SHARED
return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new;
+# else
+ if (_dlerror_run (dlmopen_doit, &args))
+ return NULL;
+
+ __libc_register_dl_open_hook ((struct link_map *) args.new);
+ __libc_register_dlfcn_hook ((struct link_map *) args.new);
+
+ return args.new;
+# endif
}
-static_link_warning (dlmopen)
+# ifdef SHARED
+strong_alias (__dlmopen, dlmopen)
+# endif
+#endif
diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
index cfd7963..6381ffc 100644
--- a/dlfcn/dlopen.c
+++ b/dlfcn/dlopen.c
@@ -20,6 +20,17 @@
#include <dlfcn.h>
#include <stddef.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlopen (const char *file, int mode)
+{
+ return __dlopen (file, mode, RETURN_ADDRESS (0));
+}
+static_link_warning (dlopen)
+
+#else
+
struct dlopen_args
{
/* The arguments for dlopen_doit. */
@@ -33,11 +44,11 @@ struct dlopen_args
/* Non-shared code has no support for multiple namespaces. */
-#ifdef SHARED
-# define NS __LM_ID_CALLER
-#else
-# define NS LM_ID_BASE
-#endif
+# ifdef SHARED
+# define NS __LM_ID_CALLER
+# else
+# define NS LM_ID_BASE
+# endif
static void
@@ -50,17 +61,34 @@ dlopen_doit (void *a)
}
-extern void *__dlopen_check (const char *file, int mode);
void *
-__dlopen_check (const char *file, int mode)
+__dlopen (const char *file, int mode DL_CALLER_DECL)
{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlopen (file, mode, DL_CALLER);
+# endif
+
struct dlopen_args args;
args.file = file;
args.mode = mode;
- args.caller = RETURN_ADDRESS (0);
+ args.caller = DL_CALLER;
+# ifdef SHARED
return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
+# else
+ if (_dlerror_run (dlopen_doit, &args))
+ return NULL;
+
+ __libc_register_dl_open_hook ((struct link_map *) args.new);
+ __libc_register_dlfcn_hook ((struct link_map *) args.new);
+
+ return args.new;
+# endif
}
-#include <shlib-compat.h>
+# ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__dlopen, __dlopen_check)
versioned_symbol (libdl, __dlopen_check, dlopen, GLIBC_2_1);
-static_link_warning (dlopen)
+# endif
+#endif
diff --git a/dlfcn/dlopenold.c b/dlfcn/dlopenold.c
index f10674a..148716c 100644
--- a/dlfcn/dlopenold.c
+++ b/dlfcn/dlopenold.c
@@ -67,6 +67,9 @@ __dlopen_nocheck (const char *file, int mode)
mode |= RTLD_LAZY;
args.mode = mode;
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlopen (file, mode, RETURN_ADDRESS (0));
+
return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
}
compat_symbol (libdl, __dlopen_nocheck, dlopen, GLIBC_2_0);
diff --git a/dlfcn/dlsym.c b/dlfcn/dlsym.c
index 76dda59..a656ca6 100644
--- a/dlfcn/dlsym.c
+++ b/dlfcn/dlsym.c
@@ -22,6 +22,16 @@
#include <ldsodefs.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlsym (void *handle, const char *name)
+{
+ return __dlsym (handle, name, RETURN_ADDRESS (0));
+}
+
+#else
+
struct dlsym_args
{
/* The arguments to dlsym_doit. */
@@ -43,10 +53,15 @@ dlsym_doit (void *a)
void *
-dlsym (void *handle, const char *name)
+__dlsym (void *handle, const char *name DL_CALLER_DECL)
{
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlsym (handle, name, DL_CALLER);
+# endif
+
struct dlsym_args args;
- args.who = RETURN_ADDRESS (0);
+ args.who = DL_CALLER;
args.handle = handle;
args.name = name;
@@ -59,3 +74,7 @@ dlsym (void *handle, const char *name)
return result;
}
+# ifdef SHARED
+strong_alias (__dlsym, dlsym)
+# endif
+#endif
diff --git a/dlfcn/dlvsym.c b/dlfcn/dlvsym.c
index 2486845..9f12764 100644
--- a/dlfcn/dlvsym.c
+++ b/dlfcn/dlvsym.c
@@ -22,6 +22,17 @@
#include <ldsodefs.h>
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+weak_function
+dlvsym (void *handle, const char *name, const char *version_str)
+{
+ return __dlvsym (handle, name, version_str, RETURN_ADDRESS (0));
+}
+
+#else
+
struct dlvsym_args
{
/* The arguments to dlvsym_doit. */
@@ -44,13 +55,18 @@ dlvsym_doit (void *a)
}
void *
-__dlvsym (void *handle, const char *name, const char *version_str)
+__dlvsym (void *handle, const char *name, const char *version_str
+ DL_CALLER_DECL)
{
- struct dlvsym_args args;
+# ifdef SHARED
+ if (__builtin_expect (_dlfcn_hook != NULL, 0))
+ return _dlfcn_hook->dlvsym (handle, name, version_str, DL_CALLER);
+# endif
+ struct dlvsym_args args;
args.handle = handle;
args.name = name;
- args.who = RETURN_ADDRESS (0);
+ args.who = DL_CALLER;
args.version = version_str;
/* Protect against concurrent loads and unloads. */
@@ -62,4 +78,7 @@ __dlvsym (void *handle, const char *name, const char *version_str)
return result;
}
+# ifdef SHARED
weak_alias (__dlvsym, dlvsym)
+# endif
+#endif
diff --git a/dlfcn/modstatic2.c b/dlfcn/modstatic2.c
new file mode 100644
index 0000000..0703de8
--- /dev/null
+++ b/dlfcn/modstatic2.c
@@ -0,0 +1,228 @@
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+int test (FILE *out, int a);
+
+int
+test (FILE *out, int a)
+{
+ fputs ("in modstatic2.c (test)\n", out);
+
+ void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
+ if (handle == NULL)
+ fprintf (out, "nonexistent: %s\n", dlerror ());
+ else
+ exit (1);
+
+ handle = dlopen ("modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+
+ int (*test2) (FILE *, int);
+ test2 = dlsym (handle, "test");
+ if (test2 == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+ if (test2 != test)
+ {
+ fprintf (out, "test %p != test2 %p\n", test, test2);
+ exit (1);
+ }
+
+ Dl_info info;
+ int res = dladdr (test2, &info);
+ if (res == 0)
+ {
+ fputs ("dladdr returned 0\n", out);
+ exit (1);
+ }
+ else
+ {
+ if (strstr (info.dli_fname, "modstatic2.so") == NULL
+ || strcmp (info.dli_sname, "test") != 0)
+ {
+ fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+ exit (1);
+ }
+ if (info.dli_saddr != (void *) test2)
+ {
+ fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
+ exit (1);
+ }
+ }
+
+ ElfW(Sym) *sym;
+ void *symp;
+ res = dladdr1 (test2, &info, &symp, RTLD_DL_SYMENT);
+ if (res == 0)
+ {
+ fputs ("dladdr1 returned 0\n", out);
+ exit (1);
+ }
+ else
+ {
+ if (strstr (info.dli_fname, "modstatic2.so") == NULL
+ || strcmp (info.dli_sname, "test") != 0)
+ {
+ fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+ exit (1);
+ }
+ if (info.dli_saddr != (void *) test2)
+ {
+ fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
+ exit (1);
+ }
+ sym = symp;
+ if (sym == NULL)
+ {
+ fputs ("sym == NULL\n", out);
+ exit (1);
+ }
+ if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+ || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+ {
+ fprintf (out, "bind %d visibility %d\n",
+ (int) ELF32_ST_BIND (sym->st_info),
+ (int) ELF32_ST_VISIBILITY (sym->st_other));
+ exit (1);
+ }
+ }
+
+ Lmid_t lmid;
+ res = dlinfo (handle, RTLD_DI_LMID, &lmid);
+ if (res != 0)
+ {
+ fprintf (out, "dlinfo returned %d %s\n", res, dlerror ());
+ exit (1);
+ }
+ else if (lmid != LM_ID_BASE)
+ {
+ fprintf (out, "lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
+ exit (1);
+ }
+
+ void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
+ if (handle2 == NULL)
+ {
+ fprintf (out, "libdl.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+#ifdef DO_VERSIONING
+ if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
+ {
+ fprintf (out, "dlvsym: %s\n", dlerror ());
+ exit (1);
+ }
+#endif
+
+ void *(*dlsymfn) (void *, const char *);
+ dlsymfn = dlsym (handle2, "dlsym");
+ if (dlsymfn == NULL)
+ {
+ fprintf (out, "dlsym \"dlsym\": %s\n", dlerror ());
+ exit (1);
+ }
+ void *test3 = dlsymfn (handle, "test");
+ if (test3 == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+ else if (test3 != (void *) test2)
+ {
+ fprintf (out, "test2 %p != test3 %p\n", test2, test3);
+ exit (1);
+ }
+
+ dlclose (handle2);
+ dlclose (handle);
+
+ handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+
+ handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ fprintf (out, "LM_ID_NEWLM: %s\n", dlerror ());
+ else
+ {
+ fputs ("LM_ID_NEWLM unexpectedly succeeded\n", out);
+ exit (1);
+ }
+
+ handle = dlopen ("modstatic.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+
+ int (*test4) (int);
+ test4 = dlsym (handle, "test");
+ if (test4 == NULL)
+ {
+ fprintf (out, "%s\n", dlerror ());
+ exit (1);
+ }
+
+ res = test4 (16);
+ if (res != 16 + 16)
+ {
+ fprintf (out, "modstatic.so (test) returned %d\n", res);
+ exit (1);
+ }
+
+ res = dladdr1 (test4, &info, &symp, RTLD_DL_SYMENT);
+ if (res == 0)
+ {
+ fputs ("dladdr1 returned 0\n", out);
+ exit (1);
+ }
+ else
+ {
+ if (strstr (info.dli_fname, "modstatic.so") == NULL
+ || strcmp (info.dli_sname, "test") != 0)
+ {
+ fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+ exit (1);
+ }
+ if (info.dli_saddr != (void *) test4)
+ {
+ fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test4);
+ exit (1);
+ }
+ sym = symp;
+ if (sym == NULL)
+ {
+ fputs ("sym == NULL\n", out);
+ exit (1);
+ }
+ if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+ || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+ {
+ fprintf (out, "bind %d visibility %d\n",
+ (int) ELF32_ST_BIND (sym->st_info),
+ (int) ELF32_ST_VISIBILITY (sym->st_other));
+ exit (1);
+ }
+ }
+
+ dlclose (handle);
+
+ fputs ("leaving modstatic2.c (test)\n", out);
+ return a + a;
+}
diff --git a/dlfcn/sdladdr.c b/dlfcn/sdladdr.c
new file mode 100644
index 0000000..c484d63
--- /dev/null
+++ b/dlfcn/sdladdr.c
@@ -0,0 +1 @@
+#include "dladdr.c"
diff --git a/dlfcn/sdladdr1.c b/dlfcn/sdladdr1.c
new file mode 100644
index 0000000..a655979
--- /dev/null
+++ b/dlfcn/sdladdr1.c
@@ -0,0 +1 @@
+#include "dladdr1.c"
diff --git a/dlfcn/sdlclose.c b/dlfcn/sdlclose.c
new file mode 100644
index 0000000..dc89b98
--- /dev/null
+++ b/dlfcn/sdlclose.c
@@ -0,0 +1 @@
+#include "dlclose.c"
diff --git a/dlfcn/sdlerror.c b/dlfcn/sdlerror.c
new file mode 100644
index 0000000..f1226a4
--- /dev/null
+++ b/dlfcn/sdlerror.c
@@ -0,0 +1 @@
+#include "dlerror.c"
diff --git a/dlfcn/sdlinfo.c b/dlfcn/sdlinfo.c
new file mode 100644
index 0000000..dcc257d
--- /dev/null
+++ b/dlfcn/sdlinfo.c
@@ -0,0 +1 @@
+#include "dlinfo.c"
diff --git a/dlfcn/sdlmopen.c b/dlfcn/sdlmopen.c
new file mode 100644
index 0000000..9630c89
--- /dev/null
+++ b/dlfcn/sdlmopen.c
@@ -0,0 +1 @@
+#include "dlmopen.c"
diff --git a/dlfcn/sdlopen.c b/dlfcn/sdlopen.c
new file mode 100644
index 0000000..1ff2eb2
--- /dev/null
+++ b/dlfcn/sdlopen.c
@@ -0,0 +1 @@
+#include "dlopen.c"
diff --git a/dlfcn/sdlsym.c b/dlfcn/sdlsym.c
new file mode 100644
index 0000000..0234f23
--- /dev/null
+++ b/dlfcn/sdlsym.c
@@ -0,0 +1 @@
+#include "dlsym.c"
diff --git a/dlfcn/sdlvsym.c b/dlfcn/sdlvsym.c
new file mode 100644
index 0000000..ec42860
--- /dev/null
+++ b/dlfcn/sdlvsym.c
@@ -0,0 +1 @@
+#include "dlvsym.c"
diff --git a/dlfcn/tststatic2.c b/dlfcn/tststatic2.c
new file mode 100644
index 0000000..85c0fb2
--- /dev/null
+++ b/dlfcn/tststatic2.c
@@ -0,0 +1,166 @@
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+int
+main (void)
+{
+ void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
+ if (handle == NULL)
+ printf ("nonexistent: %s\n", dlerror ());
+ else
+ exit (1);
+
+ handle = dlopen ("modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+
+ int (*test) (FILE *, int);
+ test = dlsym (handle, "test");
+ if (test == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+
+ Dl_info info;
+ int res = dladdr (test, &info);
+ if (res == 0)
+ {
+ puts ("dladdr returned 0");
+ exit (1);
+ }
+ else
+ {
+ if (strstr (info.dli_fname, "modstatic2.so") == NULL
+ || strcmp (info.dli_sname, "test") != 0)
+ {
+ printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
+ exit (1);
+ }
+ if (info.dli_saddr != (void *) test)
+ {
+ printf ("saddr %p != test %p\n", info.dli_saddr, test);
+ exit (1);
+ }
+ }
+
+ ElfW(Sym) *sym;
+ void *symp;
+ res = dladdr1 (test, &info, &symp, RTLD_DL_SYMENT);
+ if (res == 0)
+ {
+ puts ("dladdr1 returned 0");
+ exit (1);
+ }
+ else
+ {
+ if (strstr (info.dli_fname, "modstatic2.so") == NULL
+ || strcmp (info.dli_sname, "test") != 0)
+ {
+ printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
+ exit (1);
+ }
+ if (info.dli_saddr != (void *) test)
+ {
+ printf ("saddr %p != test %p\n", info.dli_saddr, test);
+ exit (1);
+ }
+ sym = symp;
+ if (sym == NULL)
+ {
+ puts ("sym == NULL\n");
+ exit (1);
+ }
+ if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+ || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+ {
+ printf ("bind %d visibility %d\n",
+ (int) ELF32_ST_BIND (sym->st_info),
+ (int) ELF32_ST_VISIBILITY (sym->st_other));
+ exit (1);
+ }
+ }
+
+ Lmid_t lmid;
+ res = dlinfo (handle, RTLD_DI_LMID, &lmid);
+ if (res != 0)
+ {
+ printf ("dlinfo returned %d %s\n", res, dlerror ());
+ exit (1);
+ }
+ else if (lmid != LM_ID_BASE)
+ {
+ printf ("lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
+ exit (1);
+ }
+
+ res = test (stdout, 2);
+ if (res != 4)
+ {
+ printf ("Got %i, expected 4\n", res);
+ exit (1);
+ }
+
+ void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
+ if (handle2 == NULL)
+ {
+ printf ("libdl.so: %s\n", dlerror ());
+ exit (1);
+ }
+
+#ifdef DO_VERSIONING
+ if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
+ {
+ printf ("dlvsym: %s\n", dlerror ());
+ exit (1);
+ }
+#endif
+
+ void *(*dlsymfn) (void *, const char *);
+ dlsymfn = dlsym (handle2, "dlsym");
+ if (dlsymfn == NULL)
+ {
+ printf ("dlsym \"dlsym\": %s\n", dlerror ());
+ exit (1);
+ }
+ void *test2 = dlsymfn (handle, "test");
+ if (test2 == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ else if (test2 != (void *) test)
+ {
+ printf ("test %p != test2 %p\n", test, test2);
+ exit (1);
+ }
+
+ dlclose (handle2);
+ dlclose (handle);
+
+ handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit (1);
+ }
+ dlclose (handle);
+
+ handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
+ if (handle == NULL)
+ printf ("LM_ID_NEWLM: %s\n", dlerror ());
+ else
+ {
+ puts ("LM_ID_NEWLM unexpectedly succeeded");
+ exit (1);
+ }
+
+ return 0;
+}