summaryrefslogtreecommitdiff
path: root/libc/dlfcn
diff options
context:
space:
mode:
authorgcc <gcc@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2006-08-17 01:18:26 +0000
committergcc <gcc@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2006-08-17 01:18:26 +0000
commit15f34685e7a9b5caf761af2ebf6afa20438d440b (patch)
treedc04ce3cdf040f198743c15b64557824de174680 /libc/dlfcn
parent1e848e0e775a36f6359161f5deb890942ef42ff3 (diff)
downloadeglibc2-15f34685e7a9b5caf761af2ebf6afa20438d440b.tar.gz
Import glibc-mainline for 2006-08-16
git-svn-id: svn://svn.eglibc.org/fsf/trunk@4 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/dlfcn')
-rw-r--r--libc/dlfcn/Makefile150
-rw-r--r--libc/dlfcn/Versions17
-rw-r--r--libc/dlfcn/bug-atexit1-lib.c375
-rw-r--r--libc/dlfcn/bug-atexit1.c23
-rw-r--r--libc/dlfcn/bug-atexit2-lib.c14
-rw-r--r--libc/dlfcn/bug-atexit2.c53
-rw-r--r--libc/dlfcn/bug-atexit3-lib.cc23
-rw-r--r--libc/dlfcn/bug-atexit3.c18
-rw-r--r--libc/dlfcn/bug-dlopen1.c12
-rw-r--r--libc/dlfcn/bug-dlsym1-lib1.c11
-rw-r--r--libc/dlfcn/bug-dlsym1-lib2.c3
-rw-r--r--libc/dlfcn/bug-dlsym1.c28
-rw-r--r--libc/dlfcn/default.c80
-rw-r--r--libc/dlfcn/defaultmod1.c64
-rw-r--r--libc/dlfcn/defaultmod2.c71
-rw-r--r--libc/dlfcn/dladdr.c45
-rw-r--r--libc/dlfcn/dladdr1.c54
-rw-r--r--libc/dlfcn/dlclose.c53
-rw-r--r--libc/dlfcn/dlerror.c252
-rw-r--r--libc/dlfcn/dlfcn.c39
-rw-r--r--libc/dlfcn/dlfcn.h192
-rw-r--r--libc/dlfcn/dlinfo.c134
-rw-r--r--libc/dlfcn/dlmopen.c108
-rw-r--r--libc/dlfcn/dlopen.c103
-rw-r--r--libc/dlfcn/dlopenold.c80
-rw-r--r--libc/dlfcn/dlsym.c80
-rw-r--r--libc/dlfcn/dlvsym.c84
-rw-r--r--libc/dlfcn/errmsg1.c48
-rw-r--r--libc/dlfcn/errmsg1mod.c26
-rw-r--r--libc/dlfcn/eval.c201
-rw-r--r--libc/dlfcn/failtest.c60
-rw-r--r--libc/dlfcn/failtestmod.c26
-rw-r--r--libc/dlfcn/glreflib1.c25
-rw-r--r--libc/dlfcn/glreflib2.c27
-rw-r--r--libc/dlfcn/glrefmain.c81
-rw-r--r--libc/dlfcn/modatexit.c44
-rw-r--r--libc/dlfcn/modcxaatexit.c41
-rw-r--r--libc/dlfcn/modstatic.c7
-rw-r--r--libc/dlfcn/modstatic2.c228
-rw-r--r--libc/dlfcn/sdladdr.c1
-rw-r--r--libc/dlfcn/sdladdr1.c1
-rw-r--r--libc/dlfcn/sdlclose.c1
-rw-r--r--libc/dlfcn/sdlerror.c1
-rw-r--r--libc/dlfcn/sdlinfo.c1
-rw-r--r--libc/dlfcn/sdlmopen.c1
-rw-r--r--libc/dlfcn/sdlopen.c1
-rw-r--r--libc/dlfcn/sdlsym.c1
-rw-r--r--libc/dlfcn/sdlvsym.c1
-rw-r--r--libc/dlfcn/tst-dladdr.c80
-rw-r--r--libc/dlfcn/tst-dlinfo.c96
-rw-r--r--libc/dlfcn/tstatexit.c71
-rw-r--r--libc/dlfcn/tstcxaatexit.c70
-rw-r--r--libc/dlfcn/tststatic.c35
-rw-r--r--libc/dlfcn/tststatic2.c166
54 files changed, 3507 insertions, 0 deletions
diff --git a/libc/dlfcn/Makefile b/libc/dlfcn/Makefile
new file mode 100644
index 000000000..649f61de6
--- /dev/null
+++ b/libc/dlfcn/Makefile
@@ -0,0 +1,150 @@
+# Copyright (C) 1995-2002, 2003, 2004, 2005, 2006 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, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+subdir := dlfcn
+headers := bits/dlfcn.h dlfcn.h
+extra-libs := libdl
+libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
+ dlmopen dlfcn
+routines := $(patsubst %,s%,$(filter-out dlfcn,$(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 modstatic2.c \
+ bug-dlsym1-lib1.c bug-dlsym1-lib2.c bug-atexit1-lib.c \
+ bug-atexit2-lib.c
+
+extra-libs-others := libdl
+
+include ../Makeconfig
+
+ifeq ($(versioning),yes)
+libdl-routines += dlopenold
+libdl-shared-only-routines := dlopenold dlfcn
+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
+ifeq (yes,$(have-protected))
+tests += tstatexit
+endif
+endif
+modules-names = glreflib1 glreflib2 failtestmod defaultmod1 defaultmod2 \
+ errmsg1mod modatexit modcxaatexit \
+ bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
+ bug-atexit2-lib bug-atexit3-lib
+
+failtestmod.so-no-z-defs = yes
+glreflib2.so-no-z-defs = yes
+errmsg1mod.so-no-z-defs = yes
+
+ifeq (yesyesyes,$(build-static)$(build-shared)$(elf))
+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)
+generated := $(modules-names:=.so)
+
+include ../Rules
+
+test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
+
+ifeq ($(build-shared),yes)
+# Build all the modules even when not actually running test programs.
+tests: $(test-modules)
+endif
+
+$(objpfx)glrefmain: $(libdl)
+$(objpfx)glrefmain.out: $(objpfx)glrefmain \
+ $(objpfx)glreflib1.so $(objpfx)glreflib2.so
+
+$(objpfx)failtest: $(libdl)
+$(objpfx)failtest.out: $(objpfx)failtestmod.so
+
+$(objpfx)tst-dladdr: $(libdl)
+$(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so
+
+$(objpfx)tst-dlinfo: $(libdl)
+$(objpfx)tst-dlinfo.out: $(objpfx)glreflib1.so
+
+LDFLAGS-default = $(LDFLAGS-rdynamic)
+$(objpfx)default: $(libdl) $(objpfx)defaultmod1.so $(objpfx)defaultmod2.so
+$(objpfx)defaultmod1.so: $(libdl) $(common-objpfx)libc_nonshared.a
+LDFLAGS-defaultmod2.so = $(LDFLAGS-Bsymbolic)
+$(objpfx)defaultmod2.so: $(libdl) $(common-objpfx)libc_nonshared.a
+
+$(objpfx)errmsg1: $(libdl)
+$(objpfx)errmsg1.out: $(objpfx)errmsg1 $(objpfx)errmsg1mod.so
+
+$(objpfx)tstatexit: $(libdl)
+$(objpfx)tstatexit.out: $(objpfx)tstatexit $(objpfx)modatexit.so
+
+$(objpfx)tstcxaatexit: $(libdl)
+$(objpfx)tstcxaatexit.out: $(objpfx)tstcxaatexit $(objpfx)modcxaatexit.so
+
+$(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)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)
+
+$(objpfx)bug-dlsym1: $(libdl) $(objpfx)bug-dlsym1-lib2.so
+$(objpfx)bug-dlsym1.out: $(objpfx)bug-dlsym1-lib1.so \
+ $(objpfx)bug-dlsym1-lib2.so
+$(objpfx)bug-dlsym1-lib1.so: $(objpfx)bug-dlsym1-lib2.so \
+ $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
+$(objpfx)bug-dlsym1-lib2.so: $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
+
+$(objpfx)bug-atexit1: $(libdl)
+$(objpfx)bug-atexit1.out: $(objpfx)bug-atexit1-lib.so
+$(objpfx)bug-atexit1-lib.so: $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
+
+$(objpfx)bug-atexit2: $(libdl)
+$(objpfx)bug-atexit2.out: $(objpfx)bug-atexit2-lib.so
+$(objpfx)bug-atexit2-lib.so: $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
+
+LDLIBS-bug-atexit3-lib.so = -lstdc++ -lgcc_eh $(common-objpfx)libc_nonshared.a
+$(objpfx)bug-atexit3: $(libdl)
+$(objpfx)bug-atexit3.out: $(objpfx)bug-atexit3-lib.so
+$(objpfx)bug-atexit3-lib.so: $(common-objpfx)libc.so \
+ $(common-objpfx)libc_nonshared.a
+
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libdl.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a \
+ $(if $(filter yes,$(elf)), $(elfobjdir)/ld.so)
diff --git a/libc/dlfcn/Versions b/libc/dlfcn/Versions
new file mode 100644
index 000000000..97902f0df
--- /dev/null
+++ b/libc/dlfcn/Versions
@@ -0,0 +1,17 @@
+libdl {
+ GLIBC_2.0 {
+ dladdr; dlclose; dlerror; dlopen; dlsym;
+ }
+ GLIBC_2.1 {
+ dlopen; dlvsym;
+ }
+ GLIBC_2.3.3 {
+ dladdr1; dlinfo;
+ }
+ GLIBC_2.3.4 {
+ dlmopen;
+ }
+ GLIBC_PRIVATE {
+ _dlfcn_hook;
+ }
+}
diff --git a/libc/dlfcn/bug-atexit1-lib.c b/libc/dlfcn/bug-atexit1-lib.c
new file mode 100644
index 000000000..715bb40b2
--- /dev/null
+++ b/libc/dlfcn/bug-atexit1-lib.c
@@ -0,0 +1,375 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int next;
+
+void
+f00 (void)
+{
+ puts ("f00");
+ if (next-- != 0)
+ _exit (1);
+}
+
+void
+f01 (void)
+{
+ puts ("f01");
+ if (next-- != 1)
+ _exit (1);
+}
+
+void
+f02 (void)
+{
+ puts ("f02");
+ if (next-- != 2)
+ _exit (1);
+}
+
+void
+f03 (void)
+{
+ puts ("f03");
+ if (next-- != 3)
+ _exit (1);
+}
+
+void
+f04 (void)
+{
+ puts ("f04");
+ if (next-- != 4)
+ _exit (1);
+}
+
+void
+f05 (void)
+{
+ puts ("f05");
+ if (next-- != 5)
+ _exit (1);
+}
+
+void
+f06 (void)
+{
+ puts ("f06");
+ if (next-- != 6)
+ _exit (1);
+}
+
+void
+f07 (void)
+{
+ puts ("f07");
+ if (next-- != 7)
+ _exit (1);
+}
+
+void
+f08 (void)
+{
+ puts ("f08");
+ if (next-- != 8)
+ _exit (1);
+}
+
+void
+f09 (void)
+{
+ puts ("f09");
+ if (next-- != 9)
+ _exit (1);
+}
+
+void
+f10 (void)
+{
+ puts ("f10");
+ if (next-- != 10)
+ _exit (1);
+}
+
+void
+f11 (void)
+{
+ puts ("f11");
+ if (next-- != 11)
+ _exit (1);
+}
+
+void
+f12 (void)
+{
+ puts ("f12");
+ if (next-- != 12)
+ _exit (1);
+}
+
+void
+f13 (void)
+{
+ puts ("f13");
+ if (next-- != 13)
+ _exit (1);
+}
+
+void
+f14 (void)
+{
+ puts ("f14");
+ if (next-- != 14)
+ _exit (1);
+}
+
+void
+f15 (void)
+{
+ puts ("f15");
+ if (next-- != 15)
+ _exit (1);
+}
+
+void
+f16 (void)
+{
+ puts ("f16");
+ if (next-- != 16)
+ _exit (1);
+}
+
+void
+f17 (void)
+{
+ puts ("f17");
+ if (next-- != 17)
+ _exit (1);
+}
+
+void
+f18 (void)
+{
+ puts ("f18");
+ if (next-- != 18)
+ _exit (1);
+}
+
+void
+f19 (void)
+{
+ puts ("f19");
+ if (next-- != 19)
+ _exit (1);
+}
+
+void
+f20 (void)
+{
+ puts ("f20");
+ if (next-- != 20)
+ _exit (1);
+}
+
+void
+f21 (void)
+{
+ puts ("f21");
+ if (next-- != 21)
+ _exit (1);
+}
+
+void
+f22 (void)
+{
+ puts ("f22");
+ if (next-- != 22)
+ _exit (1);
+}
+
+void
+f23 (void)
+{
+ puts ("f23");
+ if (next-- != 23)
+ _exit (1);
+}
+
+void
+f24 (void)
+{
+ puts ("f24");
+ if (next-- != 24)
+ _exit (1);
+}
+
+void
+f25 (void)
+{
+ puts ("f25");
+ if (next-- != 25)
+ _exit (1);
+}
+
+void
+f26 (void)
+{
+ puts ("f26");
+ if (next-- != 26)
+ _exit (1);
+}
+
+void
+f27 (void)
+{
+ puts ("f27");
+ if (next-- != 27)
+ _exit (1);
+}
+
+void
+f28 (void)
+{
+ puts ("f28");
+ if (next-- != 28)
+ _exit (1);
+}
+
+void
+f29 (void)
+{
+ puts ("f29");
+ if (next-- != 29)
+ _exit (1);
+}
+
+void
+f30 (void)
+{
+ puts ("f30");
+ if (next-- != 30)
+ _exit (1);
+}
+
+void
+f31 (void)
+{
+ puts ("f31");
+ if (next-- != 31)
+ _exit (1);
+}
+
+void
+f32 (void)
+{
+ puts ("f32");
+ if (next-- != 32)
+ _exit (1);
+}
+
+void
+f33 (void)
+{
+ puts ("f33");
+ if (next-- != 33)
+ _exit (1);
+}
+
+void
+f34 (void)
+{
+ puts ("f34");
+ if (next-- != 34)
+ _exit (1);
+}
+
+void
+f35 (void)
+{
+ puts ("f35");
+ if (next-- != 35)
+ _exit (1);
+}
+
+void
+f36 (void)
+{
+ puts ("f36");
+ if (next-- != 36)
+ _exit (1);
+}
+
+void
+f37 (void)
+{
+ puts ("f37");
+ if (next-- != 37)
+ _exit (1);
+}
+
+void
+f38 (void)
+{
+ puts ("f38");
+ if (next-- != 38)
+ _exit (1);
+}
+
+void
+f39 (void)
+{
+ puts ("f39");
+ if (next-- != 39)
+ _exit (1);
+}
+
+void
+foo (void)
+{
+ atexit (f00);
+ atexit (f01);
+ atexit (f02);
+ atexit (f03);
+ atexit (f04);
+ atexit (f05);
+ atexit (f06);
+ atexit (f07);
+ atexit (f08);
+ atexit (f09);
+
+ atexit (f10);
+ atexit (f11);
+ atexit (f12);
+ atexit (f13);
+ atexit (f14);
+ atexit (f15);
+ atexit (f16);
+ atexit (f17);
+ atexit (f18);
+ atexit (f19);
+
+ atexit (f20);
+ atexit (f21);
+ atexit (f22);
+ atexit (f23);
+ atexit (f24);
+ atexit (f25);
+ atexit (f26);
+ atexit (f27);
+ atexit (f28);
+ atexit (f29);
+
+ atexit (f30);
+ atexit (f31);
+ atexit (f32);
+ atexit (f33);
+ atexit (f34);
+ atexit (f35);
+ atexit (f36);
+ atexit (f37);
+ atexit (f38);
+ atexit (f39);
+
+ next = 39;
+}
diff --git a/libc/dlfcn/bug-atexit1.c b/libc/dlfcn/bug-atexit1.c
new file mode 100644
index 000000000..e2d1d2f77
--- /dev/null
+++ b/libc/dlfcn/bug-atexit1.c
@@ -0,0 +1,23 @@
+/* Derived from a test case in
+ http://sourceware.org/bugzilla/show_bug.cgi?id=1158. */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+ for (int i = 0; i < 2; ++i)
+ {
+ void *dso = dlopen ("$ORIGIN/bug-atexit1-lib.so", RTLD_NOW);
+ void (*fn) (void) = (void (*) (void)) dlsym (dso, "foo");
+ fn ();
+ dlclose (dso);
+ puts ("round done");
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/bug-atexit2-lib.c b/libc/dlfcn/bug-atexit2-lib.c
new file mode 100644
index 000000000..ca3965756
--- /dev/null
+++ b/libc/dlfcn/bug-atexit2-lib.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+fx (void)
+{
+ puts ("At exit fx");
+}
+
+void
+foo (void)
+{
+ atexit (fx);
+}
diff --git a/libc/dlfcn/bug-atexit2.c b/libc/dlfcn/bug-atexit2.c
new file mode 100644
index 000000000..15e9f7aa0
--- /dev/null
+++ b/libc/dlfcn/bug-atexit2.c
@@ -0,0 +1,53 @@
+/* Derived from a test case in
+ http://sourceware.org/bugzilla/show_bug.cgi?id=1158. */
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int next = 3;
+
+static void
+f1 (void)
+{
+ puts ("f1");
+ if (next-- != 1)
+ _exit (1);
+}
+
+static void
+f2 (void)
+{
+ puts ("f2");
+ if (next-- != 2)
+ _exit (1);
+}
+
+static void
+f3 (void)
+{
+ puts ("f3");
+ if (next-- != 3)
+ _exit (1);
+}
+
+static int
+do_test (void)
+{
+ atexit (f1);
+
+ void *dso = dlopen ("$ORIGIN/bug-atexit2-lib.so", RTLD_NOW);
+ void (*fn) (void) = (void (*) (void)) dlsym (dso, "foo");
+ fn ();
+
+ atexit (f2);
+
+ dlclose (dso);
+
+ atexit (f3);
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/bug-atexit3-lib.cc b/libc/dlfcn/bug-atexit3-lib.cc
new file mode 100644
index 000000000..3d01ea81d
--- /dev/null
+++ b/libc/dlfcn/bug-atexit3-lib.cc
@@ -0,0 +1,23 @@
+#include <unistd.h>
+
+struct statclass
+{
+ statclass()
+ {
+ write (1, "statclass\n", 10);
+ }
+ ~statclass()
+ {
+ write (1, "~statclass\n", 11);
+ }
+};
+
+struct extclass
+{
+ ~extclass()
+ {
+ static statclass var;
+ }
+};
+
+extclass globvar;
diff --git a/libc/dlfcn/bug-atexit3.c b/libc/dlfcn/bug-atexit3.c
new file mode 100644
index 000000000..897eca8a8
--- /dev/null
+++ b/libc/dlfcn/bug-atexit3.c
@@ -0,0 +1,18 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+ void *handle = dlopen ("$ORIGIN/bug-atexit3-lib.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("dlopen failed: %s\n", dlerror ());
+ return 1;
+ }
+ dlclose (handle);
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/bug-dlopen1.c b/libc/dlfcn/bug-dlopen1.c
new file mode 100644
index 000000000..d91810a4f
--- /dev/null
+++ b/libc/dlfcn/bug-dlopen1.c
@@ -0,0 +1,12 @@
+/* Test case by Bruno Haible. It test whether the dynamic string
+ token expansion can handle $ signs which do not start one of the
+ recognized keywords. */
+
+#include <dlfcn.h>
+
+int main (void)
+{
+ dlopen ("gnu-gettext-GetURL$1", RTLD_GLOBAL | RTLD_LAZY);
+ dlopen ("gnu-gettext-GetURL${1", RTLD_GLOBAL | RTLD_LAZY);
+ return 0;
+}
diff --git a/libc/dlfcn/bug-dlsym1-lib1.c b/libc/dlfcn/bug-dlsym1-lib1.c
new file mode 100644
index 000000000..4eca2519f
--- /dev/null
+++ b/libc/dlfcn/bug-dlsym1-lib1.c
@@ -0,0 +1,11 @@
+/* Test module for bug-dlsym1.c test case. */
+
+extern int dlopen_test_variable;
+
+extern char foo (void);
+
+/* here to get the unresolved symbol in our .so */
+char foo(void)
+{
+ return dlopen_test_variable;
+}
diff --git a/libc/dlfcn/bug-dlsym1-lib2.c b/libc/dlfcn/bug-dlsym1-lib2.c
new file mode 100644
index 000000000..4466cbd2d
--- /dev/null
+++ b/libc/dlfcn/bug-dlsym1-lib2.c
@@ -0,0 +1,3 @@
+/* Test module for bug-dlsym1.c test case. */
+
+char dlopen_test_variable;
diff --git a/libc/dlfcn/bug-dlsym1.c b/libc/dlfcn/bug-dlsym1.c
new file mode 100644
index 000000000..3bbf6a2f0
--- /dev/null
+++ b/libc/dlfcn/bug-dlsym1.c
@@ -0,0 +1,28 @@
+/* Test case for bug in dlsym accessing dependency objects' symbols. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+int main(void)
+{
+ void *handle;
+ char *c;
+
+ /* open lib1.so, which has the unresolved test symbol and a DT_NEEDED
+ on lib2.so, which provides the symbol */
+ if ((handle = dlopen("bug-dlsym1-lib1.so", RTLD_NOW)) == NULL) {
+ printf("dlopen(\"bug-dlsym1-lib1.so\"): %s\n", dlerror());
+ abort();
+ }
+
+ if ((c = dlsym(handle, "dlopen_test_variable")) == NULL) {
+ printf("dlsym(handle, \"dlopen_test_variable\"): %s\n", dlerror());
+ abort();
+ }
+
+ (void) dlclose(handle);
+
+ return 0;
+}
diff --git a/libc/dlfcn/default.c b/libc/dlfcn/default.c
new file mode 100644
index 000000000..eeed5a950
--- /dev/null
+++ b/libc/dlfcn/default.c
@@ -0,0 +1,80 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+
+extern int test_in_mod1 (void *);
+extern int test_in_mod2 (void *);
+
+
+int
+main (int argc, char *argv[])
+{
+ int (*ifp) (void);
+ void *p;
+ int result = 0;
+ Dl_info info;
+
+ dladdr(main, &info);
+ if (info.dli_fname == NULL)
+ {
+ printf ("%s: dladdr returns NULL dli_fname\n", __FILE__);
+ result = 1;
+ }
+ else if (strcmp (info.dli_fname, argv[0]))
+ {
+ printf ("%s: dladdr returned '%s' as dli_fname\n", __FILE__, info.dli_fname);
+ result = 1;
+ }
+ else
+ printf ("%s: dladdr returned correct dli_fname\n", __FILE__);
+
+ /* Find function `main'. */
+ p = dlsym (RTLD_DEFAULT, "main");
+ if (p == NULL)
+ {
+ printf ("%s: main not found\n", __FILE__);
+ result = 1;
+ }
+ else if ((int (*)(int, char **))p != main)
+ {
+ printf ("%s: wrong address returned for main\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: main correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod1");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod1 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 1)
+ {
+ printf ("%s: wrong address returned for found_in_mod1\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod1 correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod2");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod2 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 2)
+ {
+ printf ("%s: wrong address returned for found_in_mod2\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod2 correctly found\n", __FILE__);
+
+ result |= test_in_mod1 (main);
+
+ result |= test_in_mod2 (main);
+
+ return result;
+}
diff --git a/libc/dlfcn/defaultmod1.c b/libc/dlfcn/defaultmod1.c
new file mode 100644
index 000000000..47d229d6b
--- /dev/null
+++ b/libc/dlfcn/defaultmod1.c
@@ -0,0 +1,64 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int found_in_mod1 (void);
+int
+found_in_mod1 (void)
+{
+ return 1;
+}
+
+
+extern int test_in_mod1 (int (*mainp)(int, char **));
+int
+test_in_mod1 (int (*mainp)(int, char **))
+{
+ int (*ifp) (void);
+ void *p;
+ int result = 0;
+
+ /* Find function `main'. */
+ p = dlsym (RTLD_DEFAULT, "main");
+ if (p == NULL)
+ {
+ printf ("%s: main not found\n", __FILE__);
+ result = 1;
+ }
+ else if ((int (*)(int, char **))p != mainp)
+ {
+ printf ("%s: wrong address returned for main\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: main correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod1");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod1 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 1)
+ {
+ printf ("%s: wrong address returned for found_in_mod1\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod1 correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod2");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod2 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 2)
+ {
+ printf ("%s: wrong address returned for found_in_mod2\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod2 correctly found\n", __FILE__);
+
+ return result;
+}
diff --git a/libc/dlfcn/defaultmod2.c b/libc/dlfcn/defaultmod2.c
new file mode 100644
index 000000000..e0b170815
--- /dev/null
+++ b/libc/dlfcn/defaultmod2.c
@@ -0,0 +1,71 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int found_in_mod1 (void);
+int
+found_in_mod1 (void)
+{
+ return 1;
+}
+
+extern int found_in_mod2 (void);
+int
+found_in_mod2 (void)
+{
+ return 2;
+}
+
+
+extern int test_in_mod2 (int (*mainp)(int, char **));
+int
+test_in_mod2 (int (*mainp)(int, char **))
+{
+ int (*ifp) (void);
+ void *p;
+ int result = 0;
+
+ /* Find function `main'. */
+ p = dlsym (RTLD_DEFAULT, "main");
+ if (p == NULL)
+ {
+ printf ("%s: main not found\n", __FILE__);
+ result = 1;
+ }
+ else if ((int (*)(int, char **))p != mainp)
+ {
+ printf ("%s: wrong address returned for main\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: main correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod1");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod1 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 1)
+ {
+ printf ("%s: wrong address returned for found_in_mod1\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod1 correctly found\n", __FILE__);
+
+ ifp = dlsym (RTLD_DEFAULT, "found_in_mod2");
+ if ((void *) ifp == NULL)
+ {
+ printf ("%s: found_in_mod2 not found\n", __FILE__);
+ result = 1;
+ }
+ else if (ifp () != 2)
+ {
+ printf ("%s: wrong address returned for found_in_mod2\n", __FILE__);
+ result = 1;
+ }
+ else
+ printf ("%s: found_in_mod2 correctly found\n", __FILE__);
+
+ return result;
+}
diff --git a/libc/dlfcn/dladdr.c b/libc/dlfcn/dladdr.c
new file mode 100644
index 000000000..d0462b94f
--- /dev/null
+++ b/libc/dlfcn/dladdr.c
@@ -0,0 +1,45 @@
+/* Locate the shared object symbol nearest a given address.
+ 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#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/libc/dlfcn/dladdr1.c b/libc/dlfcn/dladdr1.c
new file mode 100644
index 000000000..0f2b603f7
--- /dev/null
+++ b/libc/dlfcn/dladdr1.c
@@ -0,0 +1,54 @@
+/* Locate the shared object symbol nearest a given address.
+ 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#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? */
+ case 0:
+ return _dl_addr (address, info, NULL, NULL);
+ case RTLD_DL_SYMENT:
+ return _dl_addr (address, info, NULL, (const ElfW(Sym) **) extra);
+ case RTLD_DL_LINKMAP:
+ return _dl_addr (address, info, (struct link_map **) extra, NULL);
+ }
+}
+# ifdef SHARED
+strong_alias (__dladdr1, dladdr1)
+# endif
+#endif
diff --git a/libc/dlfcn/dlclose.c b/libc/dlfcn/dlclose.c
new file mode 100644
index 000000000..5a344f31c
--- /dev/null
+++ b/libc/dlfcn/dlclose.c
@@ -0,0 +1,53 @@
+/* Close a handle opened by `dlopen'.
+ 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+
+#if !defined SHARED && defined IS_IN_libdl
+
+int
+dlclose (void *handle)
+{
+ return __dlclose (handle);
+}
+
+#else
+
+static void
+dlclose_doit (void *handle)
+{
+ GLRO(dl_close) (handle);
+}
+
+int
+__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/libc/dlfcn/dlerror.c b/libc/dlfcn/dlerror.c
new file mode 100644
index 000000000..7ea31d439
--- /dev/null
+++ b/libc/dlfcn/dlerror.c
@@ -0,0 +1,252 @@
+/* Return error detail for failing <dlfcn.h> functions.
+ Copyright (C) 1995-2000,2002,2003,2004,2005 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <libintl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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
+ {
+ int errcode;
+ int returned;
+ bool malloced;
+ const char *objname;
+ const char *errstring;
+ };
+static struct dl_action_result last_result;
+static struct dl_action_result *static_buf;
+
+/* This is the key for the thread specific memory. */
+static __libc_key_t key;
+__libc_once_define (static, once);
+
+/* Destructor for the thread-specific data. */
+static void init (void);
+static void free_key_mem (void *mem);
+
+
+char *
+__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);
+
+ /* Get error string. */
+ result = (struct dl_action_result *) __libc_getspecific (key);
+ if (result == NULL)
+ result = &last_result;
+
+ /* Test whether we already returned the string. */
+ if (result->returned != 0)
+ {
+ /* We can now free the string. */
+ if (result->errstring != NULL)
+ {
+ if (strcmp (result->errstring, "out of memory") != 0)
+ free ((char *) result->errstring);
+ result->errstring = NULL;
+ }
+ }
+ else if (result->errstring != NULL)
+ {
+ buf = (char *) result->errstring;
+ int n;
+ if (result->errcode == 0)
+ n = __asprintf (&buf, "%s%s%s",
+ result->objname,
+ result->objname[0] == '\0' ? "" : ": ",
+ _(result->errstring));
+ else
+ n = __asprintf (&buf, "%s%s%s: %s",
+ result->objname,
+ result->objname[0] == '\0' ? "" : ": ",
+ _(result->errstring),
+ strerror (result->errcode));
+ if (n != -1)
+ {
+ /* We don't need the error string anymore. */
+ if (strcmp (result->errstring, "out of memory") != 0)
+ free ((char *) result->errstring);
+ result->errstring = buf;
+ }
+
+ /* Mark the error as returned. */
+ result->returned = 1;
+ }
+
+ return buf;
+}
+# ifdef SHARED
+strong_alias (__dlerror, dlerror)
+# endif
+
+int
+internal_function
+_dlerror_run (void (*operate) (void *), void *args)
+{
+ struct dl_action_result *result;
+
+ /* If we have not yet initialized the buffer do it now. */
+ __libc_once (once, init);
+
+ /* Get error string and number. */
+ if (static_buf != NULL)
+ result = static_buf;
+ else
+ {
+ /* We don't use the static buffer and so we have a key. Use it
+ to get the thread-specific buffer. */
+ result = __libc_getspecific (key);
+ if (result == NULL)
+ {
+ result = (struct dl_action_result *) calloc (1, sizeof (*result));
+ if (result == NULL)
+ /* We are out of memory. Since this is no really critical
+ situation we carry on by using the global variable.
+ This might lead to conflicts between the threads but
+ they soon all will have memory problems. */
+ result = &last_result;
+ else
+ /* Set the tsd. */
+ __libc_setspecific (key, result);
+ }
+ }
+
+ if (result->errstring != NULL)
+ {
+ /* Free the error string from the last failed command. This can
+ happen if `dlerror' was not run after an error was found. */
+ if (result->malloced)
+ free ((char *) result->errstring);
+ result->errstring = NULL;
+ }
+
+ result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
+ &result->malloced, operate, args);
+
+ /* If no error we mark that no error string is available. */
+ result->returned = result->errstring == NULL;
+
+ return result->errstring != NULL;
+}
+
+
+/* Initialize buffers for results. */
+static void
+init (void)
+{
+ if (__libc_key_create (&key, free_key_mem))
+ /* Creating the key failed. This means something really went
+ wrong. In any case use a static buffer which is better than
+ nothing. */
+ static_buf = &last_result;
+}
+
+
+static void
+check_free (struct dl_action_result *rec)
+{
+ if (rec->errstring != NULL
+ && strcmp (rec->errstring, "out of memory") != 0)
+ {
+ /* We can free the string only if the allocation happened in the
+ C library used by the dynamic linker. This means, it is
+ always the C library in the base namespave. */
+ struct link_map *map = NULL;
+ Dl_info info;
+ if (_dl_addr (check_free, &info, &map, NULL) != 0
+ && map != NULL && map->l_ns == 0)
+ free ((char *) rec->errstring);
+ }
+}
+
+
+static void
+__attribute__ ((destructor))
+fini (void)
+{
+ check_free (&last_result);
+}
+
+
+/* Free the thread specific data, this is done if a thread terminates. */
+static void
+free_key_mem (void *mem)
+{
+ check_free ((struct dl_action_result *) 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/libc/dlfcn/dlfcn.c b/libc/dlfcn/dlfcn.c
new file mode 100644
index 000000000..1ee225ba4
--- /dev/null
+++ b/libc/dlfcn/dlfcn.c
@@ -0,0 +1,39 @@
+/* Load a shared object at run time.
+ Copyright (C) 2005 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+
+
+int __dlfcn_argc attribute_hidden;
+char **__dlfcn_argv attribute_hidden;
+
+
+static void
+init (int argc, char *argv[])
+{
+ __dlfcn_argc = argc;
+ __dlfcn_argv = argv;
+}
+
+static void (*const init_array []) (int argc, char *argv[])
+ __attribute__ ((section (".init_array"), aligned (sizeof (void *))))
+ __attribute_used__ =
+{
+ init
+};
diff --git a/libc/dlfcn/dlfcn.h b/libc/dlfcn/dlfcn.h
new file mode 100644
index 000000000..7e373eddf
--- /dev/null
+++ b/libc/dlfcn/dlfcn.h
@@ -0,0 +1,192 @@
+/* User functions for run-time dynamic loading.
+ Copyright (C) 1995-1999,2000,2001,2003,2004,2006
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _DLFCN_H
+#define _DLFCN_H 1
+
+#include <features.h>
+#define __need_size_t
+#include <stddef.h>
+
+/* Collect various system dependent definitions and declarations. */
+#include <bits/dlfcn.h>
+
+
+#ifdef __USE_GNU
+/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT
+ the run-time address of the symbol called NAME in the next shared
+ object is returned. The "next" relation is defined by the order
+ the shared objects were loaded. */
+# define RTLD_NEXT ((void *) -1l)
+
+/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT
+ the run-time address of the symbol called NAME in the global scope
+ is returned. */
+# define RTLD_DEFAULT ((void *) 0)
+
+
+/* Type for namespace indeces. */
+typedef long int Lmid_t;
+
+/* Special namespace ID values. */
+# define LM_ID_BASE 0 /* Initial namespace. */
+# define LM_ID_NEWLM -1 /* For dlmopen: request new namespace. */
+#endif
+
+
+__BEGIN_DECLS
+
+/* Open the shared object FILE and map it in; return a handle that can be
+ passed to `dlsym' to get symbol values from it. */
+extern void *dlopen (__const char *__file, int __mode) __THROW;
+
+/* Unmap and close a shared object opened by `dlopen'.
+ The handle cannot be used again after calling `dlclose'. */
+extern int dlclose (void *__handle) __THROW __nonnull ((1));
+
+/* Find the run-time address in the shared object HANDLE refers to
+ of the symbol called NAME. */
+extern void *dlsym (void *__restrict __handle,
+ __const char *__restrict __name) __THROW __nonnull ((2));
+
+#ifdef __USE_GNU
+/* Like `dlopen', but request object to be allocated in a new namespace. */
+extern void *dlmopen (Lmid_t __nsid, __const char *__file, int __mode) __THROW;
+
+/* 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,
+ __const char *__restrict __name,
+ __const char *__restrict __version)
+ __THROW __nonnull ((2, 3));
+#endif
+
+/* When any of the above functions fails, call this function
+ to return a string describing the error. Each call resets
+ the error string so that a following call returns null. */
+extern char *dlerror (void) __THROW;
+
+
+#ifdef __USE_GNU
+/* Structure containing information about object searched using
+ `dladdr'. */
+typedef struct
+{
+ __const char *dli_fname; /* File name of defining object. */
+ void *dli_fbase; /* Load address of that object. */
+ __const char *dli_sname; /* Name of nearest symbol. */
+ void *dli_saddr; /* Exact value of nearest symbol. */
+} Dl_info;
+
+/* Fill in *INFO with the following information about ADDRESS.
+ Returns 0 iff no shared object's segments contain that address. */
+extern int dladdr (__const void *__address, Dl_info *__info)
+ __THROW __nonnull ((2));
+
+/* Same as `dladdr', but additionally sets *EXTRA_INFO according to FLAGS. */
+extern int dladdr1 (__const void *__address, Dl_info *__info,
+ void **__extra_info, int __flags) __THROW __nonnull ((2));
+
+/* These are the possible values for the FLAGS argument to `dladdr1'.
+ This indicates what extra information is stored at *EXTRA_INFO.
+ It may also be zero, in which case the EXTRA_INFO argument is not used. */
+enum
+ {
+ /* Matching symbol table entry (const ElfNN_Sym *). */
+ RTLD_DL_SYMENT = 1,
+
+ /* The object containing the address (struct link_map *). */
+ RTLD_DL_LINKMAP = 2
+ };
+
+
+/* Get information about the shared object HANDLE refers to.
+ REQUEST is from among the values below, and determines the use of ARG.
+
+ On success, returns zero. On failure, returns -1 and records an error
+ message to be fetched with `dlerror'. */
+extern int dlinfo (void *__restrict __handle,
+ int __request, void *__restrict __arg)
+ __THROW __nonnull ((1, 3));
+
+/* These are the possible values for the REQUEST argument to `dlinfo'. */
+enum
+ {
+ /* Treat ARG as `lmid_t *'; store namespace ID for HANDLE there. */
+ RTLD_DI_LMID = 1,
+
+ /* Treat ARG as `struct link_map **';
+ store the `struct link_map *' for HANDLE there. */
+ RTLD_DI_LINKMAP = 2,
+
+ RTLD_DI_CONFIGADDR = 3, /* Unsupported, defined by Solaris. */
+
+ /* Treat ARG as `Dl_serinfo *' (see below), and fill in to describe the
+ directories that will be searched for dependencies of this object.
+ RTLD_DI_SERINFOSIZE fills in just the `dls_cnt' and `dls_size'
+ entries to indicate the size of the buffer that must be passed to
+ RTLD_DI_SERINFO to fill in the full information. */
+ RTLD_DI_SERINFO = 4,
+ RTLD_DI_SERINFOSIZE = 5,
+
+ /* Treat ARG as `char *', and store there the directory name used to
+ expand $ORIGIN in this shared object's dependency file names. */
+ RTLD_DI_ORIGIN = 6,
+
+ RTLD_DI_PROFILENAME = 7, /* Unsupported, defined by Solaris. */
+ RTLD_DI_PROFILEOUT = 8, /* Unsupported, defined by Solaris. */
+
+ /* Treat ARG as `size_t *', and store there the TLS module ID
+ of this object's PT_TLS segment, as used in TLS relocations;
+ store zero if this object does not define a PT_TLS segment. */
+ RTLD_DI_TLS_MODID = 9,
+
+ /* Treat ARG as `void **', and store there a pointer to the calling
+ thread's TLS block corresponding to this object's PT_TLS segment.
+ Store a null pointer if this object does not define a PT_TLS
+ segment, or if the calling thread has not allocated a block for it. */
+ RTLD_DI_TLS_DATA = 10,
+
+ RTLD_DI_MAX = 10,
+ };
+
+
+/* This is the type of elements in `Dl_serinfo', below.
+ The `dls_name' member points to space in the buffer passed to `dlinfo'. */
+typedef struct
+{
+ char *dls_name; /* Name of library search path directory. */
+ unsigned int dls_flags; /* Indicates where this directory came from. */
+} Dl_serpath;
+
+/* This is the structure that must be passed (by reference) to `dlinfo' for
+ the RTLD_DI_SERINFO and RTLD_DI_SERINFOSIZE requests. */
+typedef struct
+{
+ size_t dls_size; /* Size in bytes of the whole buffer. */
+ unsigned int dls_cnt; /* Number of elements in `dls_serpath'. */
+ Dl_serpath dls_serpath[1]; /* Actually longer, dls_cnt elements. */
+} Dl_serinfo;
+#endif /* __USE_GNU */
+
+
+__END_DECLS
+
+#endif /* dlfcn.h */
diff --git a/libc/dlfcn/dlinfo.c b/libc/dlfcn/dlinfo.c
new file mode 100644
index 000000000..b1e2b009a
--- /dev/null
+++ b/libc/dlfcn/dlinfo.c
@@ -0,0 +1,134 @@
+/* dlinfo -- Get information from the dynamic linker.
+ Copyright (C) 2003, 2004, 2006 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <link.h>
+#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
+
+# ifdef USE_TLS
+# include <dl-tls.h>
+# endif
+
+struct dlinfo_args
+{
+ ElfW(Addr) caller;
+ void *handle;
+ int request;
+ void *arg;
+};
+
+static void
+dlinfo_doit (void *argsblock)
+{
+ struct dlinfo_args *const args = argsblock;
+ struct link_map *l = args->handle;
+
+# if 0
+ if (args->handle == RTLD_SELF)
+ {
+ Lmid_t nsid;
+
+ /* Find the highest-addressed object that CALLER is not below. */
+ for (nsid = 0; nsid < DL_NNS; ++nsid)
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+ if (caller >= l->l_map_start && caller < l->l_map_end)
+ /* There must be exactly one DSO for the range of the virtual
+ memory. Otherwise something is really broken. */
+ break;
+
+ if (l == NULL)
+ GLRO(dl_signal_error) (0, NULL, NULL, N_("\
+RTLD_SELF used in code not dynamically loaded"));
+ }
+# endif
+
+ switch (args->request)
+ {
+ case RTLD_DI_CONFIGADDR:
+ default:
+ GLRO(dl_signal_error) (0, NULL, NULL, N_("unsupported dlinfo request"));
+ break;
+
+ case RTLD_DI_LMID:
+ *(Lmid_t *) args->arg = l->l_ns;
+ break;
+
+ case RTLD_DI_LINKMAP:
+ *(struct link_map **) args->arg = l;
+ break;
+
+ case RTLD_DI_SERINFO:
+ _dl_rtld_di_serinfo (l, args->arg, false);
+ break;
+ case RTLD_DI_SERINFOSIZE:
+ _dl_rtld_di_serinfo (l, args->arg, true);
+ break;
+
+ case RTLD_DI_ORIGIN:
+ strcpy (args->arg, l->l_origin);
+ break;
+
+ case RTLD_DI_TLS_MODID:
+ *(size_t *) args->arg = 0;
+#ifdef USE_TLS
+ *(size_t *) args->arg = l->l_tls_modid;
+#endif
+ break;
+
+ case RTLD_DI_TLS_DATA:
+ {
+ void *data = NULL;
+#ifdef USE_TLS
+ if (l->l_tls_modid != 0)
+ data = _dl_tls_get_addr_soft (l);
+#endif
+ *(void **) args->arg = data;
+ break;
+ }
+ }
+}
+
+int
+__dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
+{
+# 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/libc/dlfcn/dlmopen.c b/libc/dlfcn/dlmopen.c
new file mode 100644
index 000000000..0c6915493
--- /dev/null
+++ b/libc/dlfcn/dlmopen.c
@@ -0,0 +1,108 @@
+/* Load a shared object at run time.
+ Copyright (C) 1995-2000,2003,2004,2006 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <unistd.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. */
+ Lmid_t nsid;
+ /* The arguments for dlopen_doit. */
+ const char *file;
+ int mode;
+ /* The return value of dlopen_doit. */
+ void *new;
+ /* Address of the caller. */
+ const void *caller;
+};
+
+static void
+dlmopen_doit (void *a)
+{
+ struct dlmopen_args *args = (struct dlmopen_args *) a;
+
+ /* Non-shared code has no support for multiple namespaces. */
+ if (args->nsid != LM_ID_BASE)
+ {
+# 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
+ GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
+
+ /* It makes no sense to use RTLD_GLOBAL when loading a DSO into
+ a namespace other than the base namespace. */
+ if (__builtin_expect (args->mode & RTLD_GLOBAL, 0))
+ GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid mode"));
+ }
+
+ args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
+ args->caller,
+ args->nsid, __dlfcn_argc, __dlfcn_argv,
+ __environ);
+}
+
+
+void *
+__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 = 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
+}
+# ifdef SHARED
+strong_alias (__dlmopen, dlmopen)
+# endif
+#endif
diff --git a/libc/dlfcn/dlopen.c b/libc/dlfcn/dlopen.c
new file mode 100644
index 000000000..bffb512aa
--- /dev/null
+++ b/libc/dlfcn/dlopen.c
@@ -0,0 +1,103 @@
+/* Load a shared object at run time.
+ Copyright (C) 1995-2000,2003,2004,2005 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <libintl.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ldsodefs.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. */
+ const char *file;
+ int mode;
+ /* The return value of dlopen_doit. */
+ void *new;
+ /* Address of the caller. */
+ const void *caller;
+};
+
+
+/* Non-shared code has no support for multiple namespaces. */
+# ifdef SHARED
+# define NS __LM_ID_CALLER
+# else
+# define NS LM_ID_BASE
+# endif
+
+
+static void
+dlopen_doit (void *a)
+{
+ struct dlopen_args *args = (struct dlopen_args *) a;
+
+ if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND
+ | RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE))
+ GLRO(dl_signal_error) (0, NULL, NULL, _("invalid mode parameter"));
+
+ args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
+ args->caller,
+ args->file == NULL ? LM_ID_BASE : NS,
+ __dlfcn_argc, __dlfcn_argv, __environ);
+}
+
+
+void *
+__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 = 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
+}
+# ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__dlopen, __dlopen_check)
+versioned_symbol (libdl, __dlopen_check, dlopen, GLIBC_2_1);
+# endif
+#endif
diff --git a/libc/dlfcn/dlopenold.c b/libc/dlfcn/dlopenold.c
new file mode 100644
index 000000000..8dae1c40c
--- /dev/null
+++ b/libc/dlfcn/dlopenold.c
@@ -0,0 +1,80 @@
+/* Load a shared object at run time.
+ Copyright (C) 1995-1999, 2000, 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+/* This file is for compatibility with glibc 2.0. Compile it only if
+ versioning is used. */
+#include <shlib-compat.h>
+#if SHLIB_COMPAT (libdl, GLIBC_2_0, GLIBC_2_1)
+
+struct dlopen_args
+{
+ /* The arguments for dlopen_doit. */
+ const char *file;
+ int mode;
+ /* The return value of dlopen_doit. */
+ void *new;
+ /* Address of the caller. */
+ const void *caller;
+};
+
+
+/* Non-shared code has no support for multiple namespaces. */
+#ifdef SHARED
+# define NS __LM_ID_CALLER
+#else
+# define NS LM_ID_BASE
+#endif
+
+
+static void
+dlopen_doit (void *a)
+{
+ struct dlopen_args *args = (struct dlopen_args *) a;
+
+ args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
+ args->caller,
+ args->file == NULL ? LM_ID_BASE : NS,
+ __dlfcn_argc, __dlfcn_argv, __environ);
+}
+
+extern void *__dlopen_nocheck (const char *file, int mode);
+void *
+__dlopen_nocheck (const char *file, int mode)
+{
+ struct dlopen_args args;
+ args.file = file;
+ args.caller = RETURN_ADDRESS (0);
+
+ if ((mode & RTLD_BINDING_MASK) == 0)
+ /* By default assume RTLD_LAZY. */
+ 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);
+#endif
diff --git a/libc/dlfcn/dlsym.c b/libc/dlfcn/dlsym.c
new file mode 100644
index 000000000..a656ca63c
--- /dev/null
+++ b/libc/dlfcn/dlsym.c
@@ -0,0 +1,80 @@
+/* Look up a symbol in a shared object loaded by `dlopen'.
+ Copyright (C) 1995-2000, 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+
+#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. */
+ void *handle;
+ const char *name;
+ void *who;
+
+ /* The return value of dlsym_doit. */
+ void *sym;
+};
+
+static void
+dlsym_doit (void *a)
+{
+ struct dlsym_args *args = (struct dlsym_args *) a;
+
+ args->sym = _dl_sym (args->handle, args->name, args->who);
+}
+
+
+void *
+__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 = DL_CALLER;
+ args.handle = handle;
+ args.name = name;
+
+ /* Protect against concurrent loads and unloads. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ void *result = (_dlerror_run (dlsym_doit, &args) ? NULL : args.sym);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ return result;
+}
+# ifdef SHARED
+strong_alias (__dlsym, dlsym)
+# endif
+#endif
diff --git a/libc/dlfcn/dlvsym.c b/libc/dlfcn/dlvsym.c
new file mode 100644
index 000000000..9f12764e8
--- /dev/null
+++ b/libc/dlfcn/dlvsym.c
@@ -0,0 +1,84 @@
+/* Look up a versioned symbol in a shared object loaded by `dlopen'.
+ Copyright (C) 1995-2000, 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
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+
+#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. */
+ void *handle;
+ const char *name;
+ const char *version;
+ void *who;
+
+ /* The return values of dlvsym_doit. */
+ void *sym;
+};
+
+
+static void
+dlvsym_doit (void *a)
+{
+ struct dlvsym_args *args = (struct dlvsym_args *)a;
+
+ args->sym = _dl_vsym (args->handle, args->name, args->version, args->who);
+}
+
+void *
+__dlvsym (void *handle, const char *name, const char *version_str
+ DL_CALLER_DECL)
+{
+# 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 = DL_CALLER;
+ args.version = version_str;
+
+ /* Protect against concurrent loads and unloads. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+
+ void *result = (_dlerror_run (dlvsym_doit, &args) ? NULL : args.sym);
+
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ return result;
+}
+# ifdef SHARED
+weak_alias (__dlvsym, dlvsym)
+# endif
+#endif
diff --git a/libc/dlfcn/errmsg1.c b/libc/dlfcn/errmsg1.c
new file mode 100644
index 000000000..f4a9a49e9
--- /dev/null
+++ b/libc/dlfcn/errmsg1.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2000 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (void)
+{
+ void *h;
+ const char *s;
+
+ /* Test that dlerror works initially. */
+ s = dlerror ();
+ printf ("dlerror() without prior dl*() call returned: %s\n", s);
+ if (s != NULL)
+ return 1;
+
+ h = dlopen ("errmsg1mod.so", RTLD_NOW);
+ if (h != NULL)
+ {
+ dlclose (h);
+ puts ("errmsg1mod.so could be loaded !?");
+ exit (1);
+ }
+
+ s = dlerror ();
+ puts (s);
+
+ return strstr (s, "errmsg1mod.so") == NULL;
+}
diff --git a/libc/dlfcn/errmsg1mod.c b/libc/dlfcn/errmsg1mod.c
new file mode 100644
index 000000000..8aa5166ce
--- /dev/null
+++ b/libc/dlfcn/errmsg1mod.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2000 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+extern int bar (void);
+extern int foo (void);
+
+int
+foo (void)
+{
+ return bar ();
+}
diff --git a/libc/dlfcn/eval.c b/libc/dlfcn/eval.c
new file mode 100644
index 000000000..e0b56624f
--- /dev/null
+++ b/libc/dlfcn/eval.c
@@ -0,0 +1,201 @@
+/* You don't really want to know what this hack is for.
+ Copyright (C) 1996, 1997, 2000, 2001 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void *funcall (char **stringp) __attribute_noinline__;
+static void *eval (char **stringp);
+
+
+long int weak_function
+__strtol_internal (const char *nptr, char **endptr, int base, int group)
+{
+ unsigned long int result = 0;
+ long int sign = 1;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ sign = -1;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0L;
+ }
+
+ assert (base == 0);
+ base = 10;
+ if (*nptr == '0')
+ {
+ if (nptr[1] == 'x' || nptr[1] == 'X')
+ {
+ base = 16;
+ nptr += 2;
+ }
+ else
+ base = 8;
+ }
+
+ while (*nptr >= '0' && *nptr <= '9')
+ {
+ unsigned long int digval = *nptr - '0';
+ if (result > LONG_MAX / 10
+ || (sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
+ : (result == ((unsigned long int) LONG_MAX + 1) / 10
+ && digval > ((unsigned long int) LONG_MAX + 1) % 10)))
+ {
+ errno = ERANGE;
+ return sign > 0 ? LONG_MAX : LONG_MIN;
+ }
+ result *= base;
+ result += digval;
+ ++nptr;
+ }
+
+ return (long int) result * sign;
+}
+
+
+static void *
+funcall (char **stringp)
+{
+ void *args[strlen (*stringp)], **ap = args;
+ void *argcookie = &args[1];
+
+ do
+ {
+ /* Evaluate the next token. */
+ *ap++ = eval (stringp);
+
+ /* Whitespace is irrelevant. */
+ while (isspace (**stringp))
+ ++*stringp;
+
+ /* Terminate at closing paren or end of line. */
+ } while (**stringp != '\0' && **stringp != ')');
+ if (**stringp != '\0')
+ /* Swallow closing paren. */
+ ++*stringp;
+
+ if (args[0] == NULL)
+ {
+ static const char unknown[] = "Unknown function\n";
+ write (1, unknown, sizeof unknown - 1);
+ return NULL;
+ }
+
+ /* Do it to it. */
+ __builtin_return (__builtin_apply (args[0],
+ &argcookie,
+ (char *) ap - (char *) &args[1]));
+}
+
+static void *
+eval (char **stringp)
+{
+ void *value;
+ char *p = *stringp, c;
+
+ /* Whitespace is irrelevant. */
+ while (isspace (*p))
+ ++p;
+
+ switch (*p)
+ {
+ case '"':
+ /* String constant. */
+ value = ++p;
+ do
+ if (*p == '\\')
+ {
+ switch (*strcpy (p, p + 1))
+ {
+ case 't':
+ *p = '\t';
+ break;
+ case 'n':
+ *p = '\n';
+ break;
+ }
+ ++p;
+ }
+ while (*p != '\0' && *p++ != '"');
+ if (p[-1] == '"')
+ p[-1] = '\0';
+ break;
+
+ case '(':
+ *stringp = ++p;
+ return funcall (stringp);
+
+ default:
+ /* Try to parse it as a number. */
+ value = (void *) __strtol_internal (p, stringp, 0, 0);
+ if (*stringp != p)
+ return value;
+
+ /* Anything else is a symbol that produces its address. */
+ value = p;
+ do
+ ++p;
+ while (*p != '\0' && !isspace (*p) && (!ispunct (*p) || *p == '_'));
+ c = *p;
+ *p = '\0';
+ value = dlsym (NULL, value);
+ *p = c;
+ break;
+ }
+
+ *stringp = p;
+ return value;
+}
+
+
+extern void _start (void) __attribute__ ((noreturn));
+void
+__attribute__ ((noreturn))
+_start (void)
+{
+ char *buf = NULL;
+ size_t bufsz = 0;
+
+ while (__getdelim (&buf, &bufsz, '\n', stdin) > 0)
+ {
+ char *p = buf;
+ eval (&p);
+ }
+
+ exit (0);
+}
diff --git a/libc/dlfcn/failtest.c b/libc/dlfcn/failtest.c
new file mode 100644
index 000000000..e0ac4ef63
--- /dev/null
+++ b/libc/dlfcn/failtest.c
@@ -0,0 +1,60 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+/* Number of rounds we perform the test. */
+#define TEST_ROUNDS 10
+
+
+static const char unknown[] = "a-file-with-this-name-does-not-exist";
+static const char exists[] = "failtestmod.so";
+
+
+int
+main (void)
+{
+ int i;
+
+ setvbuf (stdout, NULL, _IONBF, 0);
+
+ for (i = 0; i < TEST_ROUNDS; ++i)
+ {
+ void *dsc;
+
+ printf ("Round %d: Try loading \"%s\"\n", i, unknown);
+
+ dsc = dlopen (unknown, RTLD_NOW);
+ if (dsc != NULL)
+ {
+ printf ("We found a file of name \"%s\": this should not happen\n",
+ unknown);
+ return 1;
+ }
+
+ printf ("Round %d: loading \"%s\" failed\n", i, unknown);
+
+ /* Don't use `dlerror', just load an existing file. */
+ dsc = dlopen (exists, RTLD_NOW);
+ if (dsc == NULL)
+ {
+ printf ("Could not load \"%s\": %s\n", exists, dlerror ());
+ return 1;
+ }
+
+ printf ("Round %d: Loaded \"%s\"\n", i, exists);
+
+ dlclose (dsc);
+
+ printf ("Round %d: Unloaded \"%s\"\n", i, exists);
+ }
+
+ return 0;
+}
+
+
+extern void foo (void);
+
+void
+foo (void)
+{
+}
diff --git a/libc/dlfcn/failtestmod.c b/libc/dlfcn/failtestmod.c
new file mode 100644
index 000000000..a03f90b73
--- /dev/null
+++ b/libc/dlfcn/failtestmod.c
@@ -0,0 +1,26 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+extern void constr (void) __attribute__ ((__constructor__));
+void
+__attribute__ ((__constructor__))
+constr (void)
+{
+ void *handle;
+ void *m;
+
+ /* Open the library. */
+ handle = dlopen (NULL, RTLD_NOW);
+ if (handle == NULL)
+ {
+ puts ("Cannot get handle to own object");
+ return;
+ }
+
+ /* Get a symbol. */
+ m = dlsym (handle, "main");
+ puts ("called dlsym() to get main");
+
+ dlclose (handle);
+}
diff --git a/libc/dlfcn/glreflib1.c b/libc/dlfcn/glreflib1.c
new file mode 100644
index 000000000..44ad52572
--- /dev/null
+++ b/libc/dlfcn/glreflib1.c
@@ -0,0 +1,25 @@
+/* Test for dependency tracking added by relocations.
+ Copyright (C) 2000 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+extern int ref1 (void);
+int
+ref1 (void)
+{
+ return 42;
+}
diff --git a/libc/dlfcn/glreflib2.c b/libc/dlfcn/glreflib2.c
new file mode 100644
index 000000000..b5630f1f0
--- /dev/null
+++ b/libc/dlfcn/glreflib2.c
@@ -0,0 +1,27 @@
+/* Test for dependency tracking added by relocations.
+ Copyright (C) 2000 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+extern int ref1 (void);
+
+extern int ref2 (void);
+int
+ref2 (void)
+{
+ return ref1 ();
+}
diff --git a/libc/dlfcn/glrefmain.c b/libc/dlfcn/glrefmain.c
new file mode 100644
index 000000000..e113ef662
--- /dev/null
+++ b/libc/dlfcn/glrefmain.c
@@ -0,0 +1,81 @@
+/* Test for dependency tracking added by relocations.
+ Copyright (C) 2000 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static void *
+load (const char *name)
+{
+ void *d = dlopen (name, RTLD_LAZY | RTLD_GLOBAL);
+ if (d == NULL)
+ error (EXIT_FAILURE, errno, "cannot load `%s'", name);
+ return d;
+}
+
+
+#define TEST_FUNCTION do_test ()
+extern int do_test (void);
+
+int
+do_test (void)
+{
+ void *d1;
+ void *d2;
+ int (*f) (void);
+
+ d1 = load ("glreflib1.so");
+ d2 = load ("glreflib2.so");
+
+ f = dlsym (d2, "ref2");
+ if (f == NULL)
+ error (EXIT_FAILURE, errno, "cannot get pointer to `%s'", "ref2");
+
+ if (f () != 42)
+ error (EXIT_FAILURE, 0, "wrong result from `%s'", "ref2");
+
+ puts ("Correct result in first call");
+ fflush (stdout);
+
+ /* Now unload the first file. */
+ dlclose (d1);
+
+ puts ("About to call the second time");
+ fflush (stdout);
+
+ /* Try calling the function again. */
+ if (f () != 42)
+ error (EXIT_FAILURE, 0, "wrong result from `%s' (second call)", "ref2");
+
+ puts ("Second call succeeded!");
+ fflush (stdout);
+
+ dlclose (d2);
+
+ puts ("glreflib2 also closed");
+ fflush (stdout);
+
+ return 0;
+}
+
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/modatexit.c b/libc/dlfcn/modatexit.c
new file mode 100644
index 000000000..710953406
--- /dev/null
+++ b/libc/dlfcn/modatexit.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2001 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int global;
+int *ip;
+
+extern void dummy (void);
+extern void foo (void *p);
+
+void
+dummy (void)
+{
+ printf ("This is %s\n", __FUNCTION__);
+ *ip = global = 1;
+}
+
+
+void
+foo (void *p)
+{
+ extern void *__dso_handle __attribute__ ((__weak__));
+ printf ("This is %s\n", __FUNCTION__);
+ atexit (dummy);
+ if (&__dso_handle) puts ("have dso handle"); else puts ("no dso handle");
+ ip = p;
+}
diff --git a/libc/dlfcn/modcxaatexit.c b/libc/dlfcn/modcxaatexit.c
new file mode 100644
index 000000000..6bb1ddff6
--- /dev/null
+++ b/libc/dlfcn/modcxaatexit.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 2001 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void fluffy (void *p);
+extern void bar (void *p);
+
+int global;
+
+void
+fluffy (void *p)
+{
+ printf ("This is %s\n", __FUNCTION__);
+ *(int *) p = global = 1;
+}
+
+
+void
+bar (void *p)
+{
+ extern void *__dso_handle;
+ printf ("This is %s\n", __FUNCTION__);
+ __cxa_atexit (fluffy, p, __dso_handle);
+}
diff --git a/libc/dlfcn/modstatic.c b/libc/dlfcn/modstatic.c
new file mode 100644
index 000000000..5ea71171c
--- /dev/null
+++ b/libc/dlfcn/modstatic.c
@@ -0,0 +1,7 @@
+extern int test (int);
+
+int
+test (int a)
+{
+ return a + a;
+}
diff --git a/libc/dlfcn/modstatic2.c b/libc/dlfcn/modstatic2.c
new file mode 100644
index 000000000..0703de851
--- /dev/null
+++ b/libc/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/libc/dlfcn/sdladdr.c b/libc/dlfcn/sdladdr.c
new file mode 100644
index 000000000..c484d63b2
--- /dev/null
+++ b/libc/dlfcn/sdladdr.c
@@ -0,0 +1 @@
+#include "dladdr.c"
diff --git a/libc/dlfcn/sdladdr1.c b/libc/dlfcn/sdladdr1.c
new file mode 100644
index 000000000..a655979bc
--- /dev/null
+++ b/libc/dlfcn/sdladdr1.c
@@ -0,0 +1 @@
+#include "dladdr1.c"
diff --git a/libc/dlfcn/sdlclose.c b/libc/dlfcn/sdlclose.c
new file mode 100644
index 000000000..dc89b9802
--- /dev/null
+++ b/libc/dlfcn/sdlclose.c
@@ -0,0 +1 @@
+#include "dlclose.c"
diff --git a/libc/dlfcn/sdlerror.c b/libc/dlfcn/sdlerror.c
new file mode 100644
index 000000000..f1226a48c
--- /dev/null
+++ b/libc/dlfcn/sdlerror.c
@@ -0,0 +1 @@
+#include "dlerror.c"
diff --git a/libc/dlfcn/sdlinfo.c b/libc/dlfcn/sdlinfo.c
new file mode 100644
index 000000000..dcc257dd1
--- /dev/null
+++ b/libc/dlfcn/sdlinfo.c
@@ -0,0 +1 @@
+#include "dlinfo.c"
diff --git a/libc/dlfcn/sdlmopen.c b/libc/dlfcn/sdlmopen.c
new file mode 100644
index 000000000..9630c89a7
--- /dev/null
+++ b/libc/dlfcn/sdlmopen.c
@@ -0,0 +1 @@
+#include "dlmopen.c"
diff --git a/libc/dlfcn/sdlopen.c b/libc/dlfcn/sdlopen.c
new file mode 100644
index 000000000..1ff2eb285
--- /dev/null
+++ b/libc/dlfcn/sdlopen.c
@@ -0,0 +1 @@
+#include "dlopen.c"
diff --git a/libc/dlfcn/sdlsym.c b/libc/dlfcn/sdlsym.c
new file mode 100644
index 000000000..0234f23f8
--- /dev/null
+++ b/libc/dlfcn/sdlsym.c
@@ -0,0 +1 @@
+#include "dlsym.c"
diff --git a/libc/dlfcn/sdlvsym.c b/libc/dlfcn/sdlvsym.c
new file mode 100644
index 000000000..ec4286058
--- /dev/null
+++ b/libc/dlfcn/sdlvsym.c
@@ -0,0 +1 @@
+#include "dlvsym.c"
diff --git a/libc/dlfcn/tst-dladdr.c b/libc/dlfcn/tst-dladdr.c
new file mode 100644
index 000000000..35f40700f
--- /dev/null
+++ b/libc/dlfcn/tst-dladdr.c
@@ -0,0 +1,80 @@
+/* Test for dladdr.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Volkmar Sieh <vs@caldera.de> and Andreas Jaeger <aj@suse.de>.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ldsodefs.h>
+
+
+#define TEST_FUNCTION do_test ()
+extern int do_test (void);
+
+int
+do_test (void)
+{
+ void *handle;
+ int (*sym) (void); /* We load ref1 from glreflib1.c. */
+ Dl_info info;
+ int ret;
+
+
+ handle = dlopen ("glreflib1.so", RTLD_NOW);
+ if (handle == NULL)
+ error (EXIT_FAILURE, 0, "cannot load: glreflib1.so");
+
+ 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");
+
+ printf ("address of ref1 = %lx\n",
+ (unsigned long int) DL_LOOKUP_ADDRESS (sym));
+ printf ("ret = %d\n", ret);
+ 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");
+
+ dlclose (handle);
+
+ return 0;
+}
+
+
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/tst-dlinfo.c b/libc/dlfcn/tst-dlinfo.c
new file mode 100644
index 000000000..70906ebdf
--- /dev/null
+++ b/libc/dlfcn/tst-dlinfo.c
@@ -0,0 +1,96 @@
+/* Test for dlinfo.
+ Copyright (C) 2003 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+
+#define TEST_FUNCTION do_test ()
+
+static int
+do_test (void)
+{
+ int status = 0;
+
+ void *handle = dlopen ("glreflib1.so", RTLD_NOW);
+ if (handle == NULL)
+ error (EXIT_FAILURE, 0, "cannot load: glreflib1.so: %s", dlerror ());
+
+#define TRY(req, arg) \
+ if (dlinfo (handle, req, arg) != 0) \
+ { \
+ printf ("dlinfo failed for %s: %s\n", #req, dlerror ()); \
+ status = 1; \
+ } \
+ else
+
+ struct link_map *l;
+ TRY (RTLD_DI_LINKMAP, &l)
+ {
+ if (l != handle)
+ {
+ printf ("bogus link_map? %p != %p\n", l, handle);
+ status = 1;
+ }
+ }
+
+ char origin[8192]; /* >= PATH_MAX, in theory */
+ TRY (RTLD_DI_ORIGIN, origin)
+ {
+ printf ("origin: %s\n", origin);
+ }
+
+ Dl_serinfo counts;
+ TRY (RTLD_DI_SERINFOSIZE, &counts)
+ {
+ Dl_serinfo *buf = alloca (counts.dls_size);
+ buf->dls_cnt = counts.dls_cnt;
+ buf->dls_size = counts.dls_size;
+ printf ("%u library directories\n", buf->dls_cnt);
+ TRY (RTLD_DI_SERINFO, buf)
+ {
+ if (counts.dls_cnt != buf->dls_cnt)
+ {
+ printf ("??? became %u library directories\n", buf->dls_cnt);
+ status = 1;
+ }
+ for (unsigned int i = 0; i < buf->dls_cnt; ++i)
+ printf ("\t%#02x\t%s\n",
+ buf->dls_serpath[i].dls_flags,
+ buf->dls_serpath[i].dls_name);
+ }
+ }
+
+ unsigned long int lmid = 0xdeadbeefUL;
+ if (dlinfo (handle, RTLD_DI_LMID, &lmid) != 0)
+ printf ("dlinfo refuses RTLD_DI_LMID: %s\n", dlerror ());
+ else
+ {
+ printf ("dlinfo RTLD_DI_LMID worked? %#lx\n", lmid);
+ status = lmid == 0xdeadbeefUL;
+ }
+
+#undef TRY
+ dlclose (handle);
+
+ return status;
+}
+
+#include "../test-skeleton.c"
diff --git a/libc/dlfcn/tstatexit.c b/libc/dlfcn/tstatexit.c
new file mode 100644
index 000000000..710d222ea
--- /dev/null
+++ b/libc/dlfcn/tstatexit.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 2001 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+extern void *__dso_handle __attribute__ ((__weak__));
+
+int
+main (void)
+{
+ const char fname[] = "modatexit.so";
+ void *h;
+ void (*fp) (void *);
+ int v = 0;
+
+ if (&__dso_handle == NULL)
+ {
+ puts ("__dso_handle not available, cannot perform the test");
+ exit (0);
+ }
+
+ h = dlopen (fname, RTLD_NOW);
+ if (h == NULL)
+ {
+ printf ("cannot open \"%s\": %s\n", fname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "foo");
+ if (fp == NULL)
+ {
+ printf ("cannot find \"foo\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ fp (&v);
+
+ if (dlclose (h) != 0)
+ {
+ printf ("cannot close \"%s\": %s\n", fname, dlerror ());
+ exit (1);
+ }
+
+ if (v != 1)
+ {
+ puts ("module unload didn't change `v'");
+ exit (1);
+ }
+
+ puts ("finishing now");
+
+ return 0;
+}
diff --git a/libc/dlfcn/tstcxaatexit.c b/libc/dlfcn/tstcxaatexit.c
new file mode 100644
index 000000000..c8dd3b537
--- /dev/null
+++ b/libc/dlfcn/tstcxaatexit.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2001 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void *__dso_handle __attribute__ ((__weak__));
+
+int
+main (void)
+{
+ const char fname[] = "modcxaatexit.so";
+ void *h;
+ void (*fp) (void *);
+ int v = 0;
+
+ if (&__dso_handle == NULL)
+ {
+ puts ("__dso_handle not available, cannot perform the test");
+ exit (0);
+ }
+
+ h = dlopen (fname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot open \"%s\": %s\n", fname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "bar");
+ if (fp == NULL)
+ {
+ printf ("cannot find \"bar\": %s\n", dlerror ());
+ exit (1);
+ }
+
+ fp (&v);
+
+ if (dlclose (h) != 0)
+ {
+ printf ("cannot close \"%s\": %s\n", fname, dlerror ());
+ exit (1);
+ }
+
+ if (v != 1)
+ {
+ puts ("module unload didn't change `v'");
+ exit (1);
+ }
+
+ puts ("finishing now");
+
+ return 0;
+}
diff --git a/libc/dlfcn/tststatic.c b/libc/dlfcn/tststatic.c
new file mode 100644
index 000000000..00695be7b
--- /dev/null
+++ b/libc/dlfcn/tststatic.c
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *handle;
+ int (*test) (int);
+ int res;
+
+ handle = dlopen ("modstatic.so", RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit(1);
+ }
+
+ test = dlsym (handle, "test");
+ if (test == NULL)
+ {
+ printf ("%s\n", dlerror ());
+ exit(1);
+ }
+
+ res = test (2);
+ if (res != 4)
+ {
+ printf ("Got %i, expected 4\n", res);
+ exit (1);
+ }
+
+ dlclose (handle);
+ return 0;
+}
diff --git a/libc/dlfcn/tststatic2.c b/libc/dlfcn/tststatic2.c
new file mode 100644
index 000000000..85c0fb2ff
--- /dev/null
+++ b/libc/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;
+}