summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog56
-rw-r--r--Makeconfig17
-rw-r--r--dlfcn/Makefile34
-rw-r--r--dlfcn/Versions8
-rw-r--r--dlfcn/dladdr.c (renamed from elf/dladdr.c)5
-rw-r--r--dlfcn/dlclose.c (renamed from elf/dlclose.c)3
-rw-r--r--dlfcn/dlerror.c (renamed from elf/dlerror.c)2
-rw-r--r--dlfcn/dlfcn.h100
-rw-r--r--dlfcn/dlopen.c (renamed from elf/dlopen.c)5
-rw-r--r--dlfcn/dlopenold.c (renamed from elf/dlopenold.c)5
-rw-r--r--dlfcn/dlsym.c51
-rw-r--r--dlfcn/dlvsym.c55
-rw-r--r--elf/Makefile47
-rw-r--r--elf/Versions13
-rw-r--r--elf/dl-close.c3
-rw-r--r--elf/dl-open.c2
-rw-r--r--elf/dl-sym.c129
-rw-r--r--elf/dlsym.c100
-rw-r--r--elf/dlvsym.c116
-rw-r--r--elf/ldsodefs.h48
-rw-r--r--grp/initgroups.c9
-rw-r--r--iconv/gconv.c5
-rw-r--r--iconv/gconv_db.c7
-rw-r--r--iconv/skeleton.c2
-rw-r--r--include/dlfcn.h48
-rw-r--r--include/ldsodefs.h15
-rw-r--r--nss/getXXbyYY_r.c2
-rw-r--r--nss/getXXent_r.c8
-rw-r--r--nss/nsswitch.h3
-rw-r--r--sysdeps/gnu/Makefile5
-rw-r--r--sysdeps/gnu/eval.c138
31 files changed, 674 insertions, 367 deletions
diff --git a/ChangeLog b/ChangeLog
index 558a16d7ab..57400df2d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,61 @@
 1999-07-07  Ulrich Drepper  <drepper@cygnus.com>
 
+	* sysdeps/gnu/Makefile (libdl-routines): Add eval.
+
+1999-07-06  Zack Weinberg  <zack@rabi.columbia.edu>
+
+	* dlfcn: New directory.  Move the following files from elf:
+	dladdr.c, dlclose.c, dlerror.c, dlfcn.h, dlopen.c,
+	dlopenold.c, dlsym.c, dlvsym.c.
+	* dlfcn/Makefile: New file.
+	* dlfcn/Versions: New file.
+	* dlfcn/dlsym.c: All ELF-specific code split out to new
+	function _dl_sym.
+	* dlfcn/dlvsym.c: All ELF-specific code split out to new
+	function _dl_vsym.
+	* elf/dl-sym.c: New file.  _dl_sym and _dl_vsym are
+	implemented here.
+
+	* dlfcn/dladdr.c: Remove all references to ELF data structures
+	or headers.
+	* dlfcn/dlclose.c: Likewise.
+	* dlfcn/dlerror.c: Likewise.
+	* dlfcn/dlopen.c: Likewise.
+	* dlfcn/dlopenold.c: Likewise.
+
+	* Makeconfig (dlfcn): New variable - set to `dlfcn' if elf is
+	yes, empty otherwise.
+	(libdl): Set to dlfcn/libdl.so or libdl.a if elf is yes,
+	depending on build-shared.
+	(subdirs): Add $(dlfcn).
+	(rpath-dirs): Add dlfcn.
+	* elf/Makefile: Remove all references to libdl or its
+	components, except the ones relating to the test cases.
+	(routines): Add dl-sym.
+	* elf/Versions (libc): Add _dl_sym and _dl_vsym for GLIBC_2.2.
+	(libdl): Delete.
+
+	* elf/dl-close.c (_dl_close): Change argument to void *.
+	* elf/dl-open.c (_dl_open): Change return type to void *.
+	* elf/eval.c: Removed.
+	* elf/ldsodefs.h: Move prototypes of _dl_catch_error,
+	_dlerror_run, _dl_open, _dl_close, _dl_addr, and
+	_dl_mcount_wrapper_check to include/dlfcn.h.  Delete
+	_CALL_DL_FCT macro.
+	* include/dlfcn.h: Also prototype _dl_sym and _dl_vsym here.
+	Include real header from dlfcn directory.
+	* include/ldsodefs.h: Removed.
+
+	* grp/initgroups.c: Use DL_CALL_FCT not _CALL_DL_FCT.
+	* nss/getXXbyYY_r.c: Likewise.
+	* nss/getXXent_r.c: Likewise.
+	* iconv/gconv.c: Likewise.  Don't include ldsodefs.h.
+	* iconv/gconv_db.c: Likewise.  Don't include ldsodefs.h.
+	* iconv/skeleton.c: Don't include ldsodefs.h.
+	* nss/nsswitch.h: Don't include ldsodefs.h.  Include dlfcn.h.
+
+1999-07-07  Ulrich Drepper  <drepper@cygnus.com>
+
 	* sysdeps/generic/setenv.c: Describe problem.
 
 	* malloc/malloc.c (request2size): Also set errno if failing.
diff --git a/Makeconfig b/Makeconfig
index 6ae27e9dc6..e1e53605ab 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -415,7 +415,7 @@ else
 default-rpath = $(libdir)
 endif
 # This is how to find at build-time things that will be installed there.
-rpath-dirs = math elf nss nis db2 rt resolv
+rpath-dirs = math elf dlfcn nss nis db2 rt resolv
 rpath-link = \
 $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
 elfobjdir := $(patsubst ../$(subdir),.,$(common-objpfx)elf)
@@ -746,6 +746,19 @@ endif
 
 -include $(common-objpfx)sysd-dirs
 
+ifeq ($(elf),yes)
+dlfcn = dlfcn
+ifeq ($(build-shared),yes)
+libdl = $(common-objpfx)dlfcn/libdl.so$(libdl.so-version)
+else
+libdl = $(common-objpfx)dlfcn/libdl.a
+endif
+else
+# No ELF - no libdl, at least for now.
+dlfcn =
+libdl =
+endif
+
 # These are the subdirectories containing the library source.  The order
 # is more or less arbitrary.  The sorting step will take care of the
 # dependencies.  Only the $(binfmt-subdir) should always be kept at the
@@ -755,7 +768,7 @@ all-subdirs = csu assert ctype db db2 locale intl catgets math setjmp signal\
 	      grp pwd posix io termios resource misc socket sysvipc gmon    \
 	      gnulib iconv iconvdata wctype manual shadow md5-crypt po argp \
 	      $(add-ons) nss localedata timezone rt debug $(sysdep-subdirs) \
-	      $(binfmt-subdir)
+	      $(dlfcn) $(binfmt-subdir)
 all-subdirs := $(filter-out $(sysdep-inhibit-subdirs),$(all-subdirs))
 
 ifeq ($(sysd-dirs-done),t)
diff --git a/dlfcn/Makefile b/dlfcn/Makefile
new file mode 100644
index 0000000000..ee8203cf68
--- /dev/null
+++ b/dlfcn/Makefile
@@ -0,0 +1,34 @@
+# Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
+# published by the Free Software Foundation; either version 2 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+subdir		:= dlfcn
+headers		:= dlfcn.h
+extra-libs	:= libdl
+libdl-routines	:= dlopen dlclose dlsym dlvsym dlerror dladdr
+distribute	:= dlopenold.c
+
+extra-libs-others := libdl
+
+include ../Makeconfig
+
+ifeq ($(versioning),yes)
+libdl-routines	+= dlopenold
+libdl-shared-only-routines := dlopenold
+endif
+
+include ../Rules
diff --git a/dlfcn/Versions b/dlfcn/Versions
new file mode 100644
index 0000000000..b99822ad08
--- /dev/null
+++ b/dlfcn/Versions
@@ -0,0 +1,8 @@
+libdl {
+  GLIBC_2.0 {
+    dladdr; dlclose; dlerror; dlopen; dlsym;
+  }
+  GLIBC_2.1 {
+    dlopen; dlvsym;
+  }
+}
diff --git a/elf/dladdr.c b/dlfcn/dladdr.c
index 3456aae9ad..2bcc25e2fd 100644
--- a/elf/dladdr.c
+++ b/dlfcn/dladdr.c
@@ -1,5 +1,5 @@
 /* Locate the shared object symbol nearest a given address.
-   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999 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
@@ -18,9 +18,6 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <dlfcn.h>
-#include <stddef.h>
-#include <elf/ldsodefs.h>
-
 
 int
 dladdr (const void *address, Dl_info *info)
diff --git a/elf/dlclose.c b/dlfcn/dlclose.c
index b25ca48d65..dea2391128 100644
--- a/elf/dlclose.c
+++ b/dlfcn/dlclose.c
@@ -1,5 +1,5 @@
 /* Close a handle opened by `dlopen'.
-   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 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
@@ -18,7 +18,6 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <dlfcn.h>
-#include <elf/ldsodefs.h>
 
 static void
 dlclose_doit (void *handle)
diff --git a/elf/dlerror.c b/dlfcn/dlerror.c
index 4716bdd272..c43d511156 100644
--- a/elf/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -22,8 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <bits/libc-lock.h>
-#include <elf/ldsodefs.h>
-
 
 /* Type for storing results of dynamic loading actions.  */
 struct dl_action_result
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
new file mode 100644
index 0000000000..76fdc3c1c9
--- /dev/null
+++ b/dlfcn/dlfcn.h
@@ -0,0 +1,100 @@
+/* User functions for run-time dynamic loading.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  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_NULL
+#include <stddef.h>
+
+/* Collect various system dependent definitions and declarations.  */
+#include <bits/dlfcn.h>
+
+/* 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	NULL
+
+__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 __P ((__const char *__file, int __mode));
+
+/* Unmap and close a shared object opened by `dlopen'.
+   The handle cannot be used again after calling `dlclose'.  */
+extern int dlclose __P ((void *__handle));
+
+/* Find the run-time address in the shared object HANDLE refers to
+   of the symbol called NAME.  */
+extern void *dlsym __P ((void *__restrict __handle,
+			 __const char *__restrict __name));
+
+#ifdef __USE_GNU
+/* Find the run-time address in the shared object HANDLE refers to
+   of the symbol called NAME with VERSION.  */
+extern void *dlvsym __P ((void *__restrict __handle,
+			  __const char *__restrict __name,
+			  __const char *__restrict __version));
+#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 __P ((void));
+
+#ifdef __USE_GNU
+/* Fill in *INFO with the following information about ADDRESS.
+   Returns 0 iff no shared object's segments contain that address.  */
+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;
+extern int dladdr __P ((const void *__address, Dl_info *__info));
+
+/* To support profiling of shared objects it is a good idea to call
+   the function found using `dlsym' using the following macro since
+   these calls do not use the PLT.  But this would mean the dynamic
+   loader has no chance to find out when the function is called.  The
+   macro applies the necessary magic so that profiling is possible.
+   Rewrite
+	foo = (*fctp) (arg1, arg2);
+   into
+        foo = DL_CALL_FCT (fctp, (arg1, arg2));
+*/
+# define DL_CALL_FCT(fctp, args) \
+  (_dl_mcount_wrapper_check (fctp), (*(fctp)) args)
+
+/* This function calls the profiling functions.  */
+extern void _dl_mcount_wrapper_check __P ((void *__selfpc));
+#endif
+
+__END_DECLS
+
+#endif	/* dlfcn.h */
diff --git a/elf/dlopen.c b/dlfcn/dlopen.c
index b72300df5c..cb49e6b142 100644
--- a/elf/dlopen.c
+++ b/dlfcn/dlopen.c
@@ -18,8 +18,6 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <dlfcn.h>
-#include <stddef.h>
-#include <elf/ldsodefs.h>
 
 struct dlopen_args
 {
@@ -27,12 +25,11 @@ struct dlopen_args
   const char *file;
   int mode;
   /* The return value of dlopen_doit.  */
-  struct link_map *new;
+  void *new;
   /* Address of the caller.  */
   const void *caller;
 };
 
-
 static void
 dlopen_doit (void *a)
 {
diff --git a/elf/dlopenold.c b/dlfcn/dlopenold.c
index 661a40579a..f453cfb881 100644
--- a/elf/dlopenold.c
+++ b/dlfcn/dlopenold.c
@@ -18,8 +18,6 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <dlfcn.h>
-#include <stddef.h>
-#include <elf/ldsodefs.h>
 
 /* This file is for compatibility with glibc 2.0.  Compile it only if
    versioning is used.  */
@@ -31,7 +29,7 @@ struct dlopen_args
   const char *file;
   int mode;
   /* The return value of dlopen_doit.  */
-  struct link_map *new;
+  void *new;
   /* Address of the caller.  */
   const void *caller;
 };
@@ -45,7 +43,6 @@ dlopen_doit (void *a)
   args->new = _dl_open (args->file ?: "", args->mode, args->caller);
 }
 
-
 void *
 __dlopen_nocheck (const char *file, int mode)
 {
diff --git a/dlfcn/dlsym.c b/dlfcn/dlsym.c
new file mode 100644
index 0000000000..9a8fcdfbe6
--- /dev/null
+++ b/dlfcn/dlsym.c
@@ -0,0 +1,51 @@
+/* Look up a symbol in a shared object loaded by `dlopen'.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+
+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)
+{
+  struct dlsym_args args;
+  args.who = __builtin_return_address (0);
+  args.handle = handle;
+  args.name = name;
+
+  return (_dlerror_run (dlsym_doit, &args) ? NULL : args.sym);
+}
diff --git a/dlfcn/dlvsym.c b/dlfcn/dlvsym.c
new file mode 100644
index 0000000000..a279b95ae9
--- /dev/null
+++ b/dlfcn/dlvsym.c
@@ -0,0 +1,55 @@
+/* Look up a versioned symbol in a shared object loaded by `dlopen'.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+
+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)
+{
+  struct dlvsym_args args;
+
+  args.handle = handle;
+  args.name = name;
+  args.who = __builtin_return_address (0);
+  args.version = version_str;
+
+  return (_dlerror_run (dlvsym_doit, &args) ? NULL : args.sym);
+}
+weak_alias (__dlvsym, dlvsym)
diff --git a/elf/Makefile b/elf/Makefile
index b5145ea025..48012ee0c4 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -22,7 +22,7 @@ subdir		:= elf
 
 headers		= elf.h bits/elfclass.h bits/dlfcn.h link.h dlfcn.h
 routines	= $(dl-routines) dl-open dl-close dl-symbol dl-support \
-		  dl-addr enbl-secure dl-profstub dl-origin dl-libc
+		  dl-addr enbl-secure dl-profstub dl-origin dl-libc dl-sym
 
 # The core dynamic linking functions are in libc for the static and
 # profiled libraries.
@@ -35,24 +35,16 @@ elide-routines.os = $(dl-routines) dl-support enbl-secure
 # ld.so uses those routines, plus some special stuff for being the program
 # interpreter and operating independent of libc.
 rtld-routines	:= rtld $(dl-routines) dl-sysdep dl-environ dl-minimal
-distribute	= $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
-		  dl-hash.h soinit.c sofini.c ldd.bash.in eval.c \
-		  genrtldtbl.awk atomicity.h dl-procinfo.h ldsodefs.h \
-		  dl-librecon.h interp.c sln.c dl-dst.h hp-timing.h \
-		  testobj1.c testobj2.c testobj3.c testobj4.c testobj5.c \
-		  testobj6.c testobj1_1.c failobj.c do-lookup.h \
-		  gen-trusted-dirs.awk
+distribute	:= $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
+		   dl-hash.h soinit.c sofini.c ldd.bash.in \
+		   genrtldtbl.awk atomicity.h dl-procinfo.h ldsodefs.h \
+		   dl-librecon.h interp.c sln.c dl-dst.h hp-timing.h \
+		   do-lookup.h sprof.c gen-trusted-dirs.awk \
+		   testobj1.c testobj2.c testobj3.c testobj4.c testobj5.c \
+		   testobj6.c testobj1_1.c failobj.c
 
 include ../Makeconfig
 
-extra-libs	 = libdl
-extra-libs-others = $(extra-libs)
-libdl-routines	:= dlopen dlclose dlsym dlvsym dlerror dladdr
-ifeq ($(versioning),yes)
-libdl-routines	+= dlopenold
-libdl-shared-only-routines := dlopenold
-endif
-
 before-compile = $(objpfx)trusted-dirs.h
 
 ifeq ($(versioning),yes)
@@ -60,7 +52,7 @@ ld-map		= $(common-objpfx)ld.so.map
 endif
 
 ifeq (yes,$(build-shared))
-extra-objs	= $(rtld-routines:=.os) soinit.os sofini.os eval.os interp.os
+extra-objs	= $(rtld-routines:=.os) soinit.os sofini.os interp.os
 generated	= librtld.os dl-allobjs.os ld.so trusted-dirs.h trusted-dirs.st
 install-others	= $(inst_slibdir)/$(rtld-installed-name)
 install-bin	= ldd
@@ -85,15 +77,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		testobj1_1 failobj
 extra-objs += $(modules-names:=.os)
 
-ifeq ($(build-shared),yes)
-libdl = $(objpfx)libdl.so$(libdl.so-version)
-else
-libdl = $(objpfx)libdl.a
-endif
-
 include ../Rules
 
-
 ifeq (yes,$(build-shared))
 # Make sure these things are built in the `make lib' pass so they can be used
 # to run programs during the `make others' pass.
@@ -163,10 +148,6 @@ $(objpfx)trusted-dirs.st: Makefile $(..)Makeconfig
 CPPFLAGS-dl-load.c = -I$(objpfx).
 CFLAGS-dl-load.c += -Wno-uninitialized
 
-# Specify the dependencies of libdl.so; its commands come from the generic
-# rule to build a shared library.
-$(objpfx)libdl.so: $(objpfx)libdl_pic.a $(common-objpfx)libc.so $(objpfx)ld.so
-
 ifeq (yes,$(build-shared))
 $(inst_slibdir)/$(rtld-version-installed-name): $(objpfx)ld.so $(+force)
 	$(do-install-program)
@@ -209,9 +190,8 @@ $(objpfx)ldd: ldd.bash.in $(common-objpfx)soversions.mk \
 	chmod 555 $@.new
 	mv -f $@.new $@
 
-
 $(objpfx)sprof: $(libdl)
-
+
 test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
 generated += $(addsuffix .so,$(modules-names))
 
@@ -251,14 +231,9 @@ $(objpfx)loadfail.out: $(objpfx)failobj.so
 
 $(objpfx)multiload: $(libdl)
 LDFLAGS-multiload = -rdynamic
-CFLAGS-multiload.c = -DOBJDIR=\"$(elf-objpfx)\"
+CFLAGS-multiload.c = -DOBJDIR=\"$(objpfx)\"
 
 $(objpfx)multiload.out: $(objpfx)testobj1.so
 
 $(objpfx)origtest: $(libdl)
 $(objpfx)origtest.out: $(objpfx)testobj1.so
-
-# muwahaha
-
-LDFLAGS-dl.so = -Wl,-dynamic-linker,$(slibdir)/$(rtld-installed-name)
-$(objpfx)libdl.so: $(objpfx)eval.os
diff --git a/elf/Versions b/elf/Versions
index 8f1981e45a..c45ba04c7c 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -7,6 +7,10 @@ libc {
     # functions used in other libraries
     _dl_mcount_wrapper; _dl_mcount_wrapper_check;
   }
+  GLIBC_2.2 {
+    # functions used in other libraries
+    _dl_sym; _dl_vsym;
+  }
 }
 
 ld.so {
@@ -45,12 +49,3 @@ ld.so {
     _dl_dst_count; _dl_dst_substitute;
   }
 }
-
-libdl {
-  GLIBC_2.0 {
-    dladdr; dlclose; dlerror; dlopen; dlsym;
-  }
-  GLIBC_2.1 {
-    dlopen; dlvsym;
-  }
-}
diff --git a/elf/dl-close.c b/elf/dl-close.c
index a738b11d50..324f49a0ec 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -36,9 +36,10 @@ __libc_lock_define (extern, _dl_load_lock)
 
 void
 internal_function
-_dl_close (struct link_map *map)
+_dl_close (void *_map)
 {
   struct link_map **list;
+  struct link_map *map = _map;
   unsigned nsearchlist;
   unsigned int i;
 
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a9d81c75a8..a3cd8a05a3 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -211,7 +211,7 @@ dl_open_worker (void *a)
 }
 
 
-struct link_map *
+void *
 internal_function
 _dl_open (const char *file, int mode, const void *caller)
 {
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
new file mode 100644
index 0000000000..441b54fe45
--- /dev/null
+++ b/elf/dl-sym.c
@@ -0,0 +1,129 @@
+/* Look up a symbol in a shared object loaded by `dlopen'.
+   Copyright (C) 1999 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <stddef.h>
+#include <setjmp.h>
+#include <libintl.h>
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+
+void *
+internal_function
+_dl_sym (void *handle, const char *name, void *who)
+{
+  ElfW(Addr) loadbase;
+  const ElfW(Sym) *ref = NULL;
+
+  if (handle == RTLD_DEFAULT)
+    /* Search the global scope.  */
+    loadbase = _dl_lookup_symbol (name, &ref, _dl_global_scope, NULL, 0);
+  else if (handle == RTLD_NEXT)
+    {
+      struct link_map *l, *match;
+      ElfW(Addr) caller = (ElfW(Addr)) who;
+
+      /* Find the highest-addressed object that CALLER is not below.  */
+      match = NULL;
+      for (l = _dl_loaded; l; l = l->l_next)
+	if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr))
+	  match = l;
+
+      if (! match)
+	_dl_signal_error (0, NULL, _("\
+RTLD_NEXT used in code not dynamically loaded"));
+
+      l = match;
+      while (l->l_loader)
+	l = l->l_loader;
+
+      loadbase = _dl_lookup_symbol_skip (name, &ref, l->l_local_scope,
+					 NULL, match);
+    }
+  else
+    {
+      /* Search the scope of the given object.  */
+      struct link_map *map = handle;
+      loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope,
+				    map->l_name, 0);
+    }
+
+  if (loadbase)
+    return (void *) (loadbase + ref->st_value);
+
+  return NULL;
+}
+
+void *
+internal_function
+_dl_vsym (void *handle, const char *name, const char *version, void *who)
+{
+  ElfW(Addr) loadbase;
+  const ElfW(Sym) *ref = NULL;
+  struct r_found_version vers;
+
+  /* Compute hash value to the version string.  */
+  vers.name = version;
+  vers.hidden = 1;
+  vers.hash = _dl_elf_hash (version);
+  /* We don't have a specific file where the symbol can be found.  */
+  vers.filename = NULL;
+
+  if (handle == RTLD_DEFAULT)
+    /* Search the global scope.  */
+    loadbase = _dl_lookup_versioned_symbol (name, &ref, _dl_global_scope,
+					    NULL, &vers, 0);
+  else if (handle == RTLD_NEXT)
+    {
+      struct link_map *l, *match;
+      ElfW(Addr) caller = (ElfW(Addr)) who;
+
+      /* Find the highest-addressed object that CALLER is not below.  */
+      match = NULL;
+      for (l = _dl_loaded; l; l = l->l_next)
+	if (caller >= l->l_addr && (!match || match->l_addr < l->l_addr))
+	  match = l;
+
+      if (! match)
+	_dl_signal_error (0, NULL, _("\
+RTLD_NEXT used in code not dynamically loaded"));
+
+      l = match;
+      while (l->l_loader)
+	l = l->l_loader;
+
+      loadbase = _dl_lookup_versioned_symbol_skip (name, &ref,
+						   l->l_local_scope,
+						   NULL, &vers, match);
+    }
+  else
+    {
+      /* Search the scope of the given object.  */
+      struct link_map *map = handle;
+      loadbase = _dl_lookup_versioned_symbol (name, &ref,
+					      map->l_local_scope,
+					      map->l_name, &vers, 0);
+    }
+
+  if (loadbase)
+    return (void *) (loadbase + ref->st_value);
+
+  return NULL;
+}
diff --git a/elf/dlsym.c b/elf/dlsym.c
deleted file mode 100644
index 6627ffc6c2..0000000000
--- a/elf/dlsym.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Look up a symbol in a shared object loaded by `dlopen'.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
-   published by the Free Software Foundation; either version 2 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <dlfcn.h>
-#include <setjmp.h>
-#include <stddef.h>
-#include <libintl.h>
-#include <elf/ldsodefs.h>
-
-struct dlsym_args
-{
-  /* The arguments to dlsym_doit.  */
-  void *handle;
-  const char *name;
-  struct r_found_version version;
-  ElfW(Addr) caller;
-  /* The return values of dlsym_doit.  */
-  ElfW(Addr) loadbase;
-  const ElfW(Sym) *ref;
-};
-
-
-static void
-dlsym_doit (void *a)
-{
-  struct dlsym_args *args = (struct dlsym_args *) a;
-  args->ref = NULL;
-
-  if (args->handle == RTLD_DEFAULT)
-    /* Search the global scope.  */
-    args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-					_dl_global_scope, NULL, 0);
-  else if (args->handle == RTLD_NEXT)
-    {
-      struct link_map *l, *match;
-
-      /* Find the highest-addressed object that CALLER is not below.  */
-      match = NULL;
-      for (l = _dl_loaded; l; l = l->l_next)
-	if (args->caller >= l->l_addr && (!match || match->l_addr < l->l_addr))
-	  match = l;
-
-      if (! match)
-	_dl_signal_error (0, NULL, _("\
-RTLD_NEXT used in code not dynamically loaded"));
-
-      l = match;
-      while (l->l_loader)
-	l = l->l_loader;
-
-      args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
-					       l->l_local_scope, NULL, match);
-
-      if (args->loadbase == 0)
-	{
-	  /* This means that no such symbol is defined.  In this case we
-	     have to provide a phony Elfxx_Sym entry since the value is
-	     referenced in `dlsym'.  */
-	  static const ElfW(Sym) null_result;
-
-	  args->ref = &null_result;
-	}
-    }
-  else
-    {
-      /* Search the scope of the given object.  */
-      struct link_map *map = args->handle;
-      args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-					  map->l_local_scope, map->l_name, 0);
-    }
-}
-
-
-void *
-dlsym (void *handle, const char *name)
-{
-  struct dlsym_args args;
-  args.caller = (ElfW(Addr)) __builtin_return_address (0);
-  args.handle = handle;
-  args.name = name;
-
-  return (_dlerror_run (dlsym_doit, &args)
-	  ? NULL : (void *) (args.loadbase + args.ref->st_value));
-}
diff --git a/elf/dlvsym.c b/elf/dlvsym.c
deleted file mode 100644
index 68e099b4f9..0000000000
--- a/elf/dlvsym.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Look up a versioned symbol in a shared object loaded by `dlopen'.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
-   published by the Free Software Foundation; either version 2 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <dlfcn.h>
-#include <setjmp.h>
-#include <stddef.h>
-#include <libintl.h>
-#include <elf/ldsodefs.h>
-
-#include <dl-hash.h>
-
-struct dlvsym_args
-{
-  /* The arguments to dlvsym_doit.  */
-  void *handle;
-  const char *name;
-  struct r_found_version version;
-  ElfW(Addr) caller;
-  /* The return values of dlvsym_doit.  */
-  ElfW(Addr) loadbase;
-  const ElfW(Sym) *ref;
-};
-
-
-static void
-dlvsym_doit (void *a)
-{
-  struct dlvsym_args *args = (struct dlvsym_args *)a;
-  args->ref = NULL;
-
-  if (args->handle == RTLD_DEFAULT)
-    /* Search the global scope.  */
-    args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
-						  _dl_global_scope,
-						  NULL, &args->version, 0);
-  else if (args->handle == RTLD_NEXT)
-    {
-      struct link_map *l, *match;
-
-      /* Find the highest-addressed object that CALLER is not below.  */
-      match = NULL;
-      for (l = _dl_loaded; l; l = l->l_next)
-	if (args->caller >= l->l_addr && (!match || match->l_addr < l->l_addr))
-	  match = l;
-
-      if (! match)
-	_dl_signal_error (0, NULL, _("\
-RTLD_NEXT used in code not dynamically loaded"));
-
-      l = match;
-      while (l->l_loader)
-	l = l->l_loader;
-
-      args->loadbase = _dl_lookup_versioned_symbol_skip (args->name,
-							 &args->ref,
-							 l->l_local_scope,
-							 NULL, &args->version,
-							 match);
-
-      if (args->loadbase == 0)
-	{
-	  /* This means that no such symbol is defined.  In this case we
-	     have to provide a phony Elfxx_Sym entry since the value is
-	     referenced in `dlsym'.  */
-	  static const ElfW(Sym) null_result;
-
-	  args->ref = &null_result;
-	}
-    }
-  else
-    {
-      /* Search the scope of the given object.  */
-      struct link_map *map = args->handle;
-      args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
-						    map->l_local_scope,
-						    map->l_name,
-						    &args->version, 0);
-    }
-}
-
-void *
-__dlvsym (void *handle, const char *name, const char *version_str)
-{
-  struct dlvsym_args args;
-
-  args.handle = handle;
-  args.name = name;
-  args.caller = (ElfW(Addr)) __builtin_return_address (0);
-
-  /* Compute hash value to the version string.  */
-  args.version.name = version_str;
-  args.version.hidden = 1;
-  args.version.hash = _dl_elf_hash (version_str);
-  /* We don't have a specific file where the symbol can be found.  */
-  args.version.filename = NULL;
-
-  return (_dlerror_run (dlvsym_doit, &args)
-	  ? NULL : (void *) (args.loadbase + args.ref->st_value));
-}
-weak_alias (__dlvsym, dlvsym)
diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h
index bd33ba15ee..844e479283 100644
--- a/elf/ldsodefs.h
+++ b/elf/ldsodefs.h
@@ -215,17 +215,6 @@ extern void _dl_signal_cerror (int errcode,
 			       const char *errstring)
      internal_function;
 
-/* Call OPERATE, catching errors from `dl_signal_error'.  If there is no
-   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING is
-   set to a string constructed from the strings passed to _dl_signal_error,
-   and the error code passed is the return value.  ERRSTRING if nonzero
-   points to a malloc'ed string which the caller has to free after use.
-   ARGS is passed as argument to OPERATE.  */
-extern int _dl_catch_error (char **errstring,
-			    void (*operate) (void *),
-			    void *args)
-     internal_function;
-
 /* Call OPERATE, receiving errors from `dl_signal_cerror'.  Unlike
    `_dl_catch_error' the operation is resumed after the OPERATE
    function returns.
@@ -235,14 +224,6 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *),
      internal_function;
 
 
-/* Helper function for <dlfcn.h> functions.  Runs the OPERATE function via
-   _dl_catch_error.  Returns zero for success, nonzero for failure; and
-   arranges for `dlerror' to return the error details.
-   ARGS is passed as argument to OPERATE.  */
-extern int _dlerror_run (void (*operate) (void *), void *args)
-     internal_function;
-
-
 /* Open the shared object NAME and map in its segments.
    LOADER's DT_RPATH is used in searching for NAME.
    If the object is already opened, returns its existing map.
@@ -267,18 +248,6 @@ extern unsigned int _dl_map_object_deps (struct link_map *map,
 extern void _dl_setup_hash (struct link_map *map) internal_function;
 
 
-/* Open the shared object NAME, relocate it, and run its initializer if it
-   hasn't already been run.  MODE is as for `dlopen' (see <dlfcn.h>).  If
-   the object is already opened, returns its existing map.  */
-extern struct link_map *_dl_open (const char *name, int mode,
-				  const void *caller)
-     internal_function;
-
-/* Close an object previously opened by _dl_open.  */
-extern void _dl_close (struct link_map *map)
-     internal_function;
-
-
 /* Search loaded objects' symbol tables for a definition of the symbol
    referred to by UNDEF.  *SYM is the symbol table entry containing the
    reference; it is replaced with the defining symbol, and the base load
@@ -324,10 +293,6 @@ extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
 						    struct link_map *skip_this)
      internal_function;
 
-/* Locate shared object containing the given address.  */
-extern int _dl_addr (const void *address, Dl_info *info)
-     internal_function;
-
 /* Look up symbol NAME in MAP's scope and return its run-time address.  */
 extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
      internal_function;
@@ -409,7 +374,6 @@ extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc);
    calling function.  */
 extern void _dl_mcount_wrapper (void *selfpc);
 
-
 /* Show the members of the auxiliary array passed up from the kernel.  */
 extern void _dl_show_auxv (void) internal_function;
 
@@ -424,18 +388,6 @@ extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform,
 							size_t *max_capstrlen)
      internal_function;
 
-
-/* When we do profiling we have the problem that uses of `dlopen'ed
-   objects don't use the PLT but instead use a pointer to the function.
-   We still want to have profiling data and in these cases we must do
-   the work of calling `_dl_mcount' ourself.  The following macros
-   helps do it.  */
-#define _CALL_DL_FCT(fctp, args) \
-  ({ if (_dl_profile_map != NULL)					      \
-       _dl_mcount_wrapper (fctp);					      \
-     (*fctp) args;							      \
-  })
-
 __END_DECLS
 
 #endif /* ldsodefs.h */
diff --git a/grp/initgroups.c b/grp/initgroups.c
index 0296625122..7b0fe8b131 100644
--- a/grp/initgroups.c
+++ b/grp/initgroups.c
@@ -26,7 +26,6 @@
 #include <sys/types.h>
 #include <nsswitch.h>
 
-
 /* Type of the lookup function.  */
 typedef enum nss_status (*initgroups_function) (const char *, gid_t,
 						long int *, long int *,
@@ -67,7 +66,7 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
   setgrent_fct = __nss_lookup_function (nip, "setgrent");
   if (setgrent_fct)
     {
-      status = _CALL_DL_FCT (setgrent_fct, ());
+      status = DL_CALL_FCT (setgrent_fct, ());
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -78,7 +77,7 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
 
   do
     {
-      while ((status = _CALL_DL_FCT (getgrent_fct,
+      while ((status = DL_CALL_FCT (getgrent_fct,
 				     (&grpbuf, tmpbuf, buflen, errnop)),
 	      status == NSS_STATUS_TRYAGAIN)
 	     && *errnop == ERANGE)
@@ -122,7 +121,7 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start,
 
  done:
   if (endgrent_fct)
-    _CALL_DL_FCT (endgrent_fct, ());
+    DL_CALL_FCT (endgrent_fct, ());
 
   return NSS_STATUS_SUCCESS;
 }
@@ -190,7 +189,7 @@ initgroups (user, group)
 	    break;
 	}
       else
-	status = _CALL_DL_FCT (fct, (user, group, &start, &size, groups, limit,
+	status = DL_CALL_FCT (fct, (user, group, &start, &size, groups, limit,
 				     &errno));
 
       /* This is really only for debugging.  */
diff --git a/iconv/gconv.c b/iconv/gconv.c
index 3120f00b3f..f51af4a4d8 100644
--- a/iconv/gconv.c
+++ b/iconv/gconv.c
@@ -23,7 +23,6 @@
 #include <gconv.h>
 #include <sys/param.h>
 #include <dlfcn.h>
-#include <ldsodefs.h>
 
 int
 internal_function
@@ -42,7 +41,7 @@ __gconv (__gconv_t cd, const unsigned char **inbuf,
 
   if (inbuf == NULL || *inbuf == NULL)
     /* We just flush.  */
-    result = _CALL_DL_FCT (cd->__steps->__fct,
+    result = DL_CALL_FCT (cd->__steps->__fct,
 			   (cd->__steps, cd->__data, NULL, NULL,
 			    converted, 1));
   else
@@ -56,7 +55,7 @@ __gconv (__gconv_t cd, const unsigned char **inbuf,
       do
 	{
 	  last_start = *inbuf;
-	  result = _CALL_DL_FCT (cd->__steps->__fct,
+	  result = DL_CALL_FCT (cd->__steps->__fct,
 				 (cd->__steps, cd->__data, inbuf, inbufend,
 				  converted, 0));
 	}
diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c
index 39292994d8..9fe075985a 100644
--- a/iconv/gconv_db.c
+++ b/iconv/gconv_db.c
@@ -26,7 +26,6 @@
 #include <bits/libc-lock.h>
 
 #include <dlfcn.h>
-#include <ldsodefs.h>
 #include <gconv_int.h>
 
 
@@ -165,7 +164,7 @@ free_derivation (void *p)
 
   for (cnt = 0; cnt < deriv->nsteps; ++cnt)
     if (deriv->steps[cnt].__end_fct)
-      _CALL_DL_FCT (deriv->steps[cnt].__end_fct, (&deriv->steps[cnt]));
+      DL_CALL_FCT (deriv->steps[cnt].__end_fct, (&deriv->steps[cnt]));
 
   /* Free the name strings.  */
   free ((char *) deriv->steps[0].__from_name);
@@ -237,7 +236,7 @@ gen_steps (struct derivation_step *best, const char *toset,
 	  /* Call the init function.  */
 	  if (result[step_cnt].__init_fct != NULL)
 	     {
-	       status = _CALL_DL_FCT (result[step_cnt].__init_fct,
+	       status = DL_CALL_FCT (result[step_cnt].__init_fct,
 				      (&result[step_cnt]));
 
 	       if (status != __GCONV_OK)
@@ -258,7 +257,7 @@ gen_steps (struct derivation_step *best, const char *toset,
 	  while (++step_cnt < *nsteps)
 	    {
 	      if (result[step_cnt].__end_fct != NULL)
-		_CALL_DL_FCT (result[step_cnt].__end_fct, (&result[step_cnt]));
+		DL_CALL_FCT (result[step_cnt].__end_fct, (&result[step_cnt]));
 #ifndef STATIC_GCONV
 	      __gconv_release_shlib (result[step_cnt].__shlib_handle);
 #endif
diff --git a/iconv/skeleton.c b/iconv/skeleton.c
index cd750ba8ae..0bcad9e6d0 100644
--- a/iconv/skeleton.c
+++ b/iconv/skeleton.c
@@ -86,8 +86,6 @@
 #ifndef STATIC_GCONV
 # include <dlfcn.h>
 #endif
-#include <ldsodefs.h>
-
 
 /* The direction objects.  */
 #if DEFINE_DIRECTION_OBJECTS || DEFINE_INIT
diff --git a/include/dlfcn.h b/include/dlfcn.h
index f875a636ae..72b9b0e83d 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -1,5 +1,5 @@
 #ifndef _DLFCN_H
-#include <elf/dlfcn.h>
+#include <dlfcn/dlfcn.h>
 
 /* Now define the internal interfaces.  */
 extern void *__dlvsym __P ((void *__handle, __const char *__name,
@@ -8,7 +8,51 @@ extern void *__dlvsym __P ((void *__handle, __const char *__name,
 extern void *__libc_dlopen  __P ((__const char *__name));
 extern void *__libc_dlsym   __P ((void *__map, __const char *__name));
 extern int   __libc_dlclose __P ((void *__map));
-extern int   _dl_addr __P ((const void *address, Dl_info *info))
+
+/* Locate shared object containing the given address.  */
+extern int _dl_addr (const void *address, Dl_info *info)
+     internal_function;
+
+/* Open the shared object NAME, relocate it, and run its initializer if it
+   hasn't already been run.  MODE is as for `dlopen' (see <dlfcn.h>).  If
+   the object is already opened, returns its existing map.  */
+extern void *_dl_open (const char *name, int mode, const void *caller)
+     internal_function;
+
+/* Close an object previously opened by _dl_open.  */
+extern void _dl_close (void *map)
+     internal_function;
+
+/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or
+   RTLD_NEXT).  WHO is the calling function, for RTLD_NEXT.  Returns
+   the symbol value, which may be NULL.  */
+extern void *_dl_sym (void *handle, const char *name, void *who)
     internal_function;
 
+/* Look up version VERSION of symbol NAME in shared object HANDLE
+   (which may be RTLD_DEFAULT or RTLD_NEXT).  WHO is the calling
+   function, for RTLD_NEXT.  Returns the symbol value, which may be
+   NULL.  */
+extern void *_dl_vsym (void *handle, const char *name, const char *version,
+		       void *who)
+    internal_function;
+     
+/* Call OPERATE, catching errors from `dl_signal_error'.  If there is no
+   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING is
+   set to a string constructed from the strings passed to _dl_signal_error,
+   and the error code passed is the return value.  ERRSTRING if nonzero
+   points to a malloc'ed string which the caller has to free after use.
+   ARGS is passed as argument to OPERATE.  */
+extern int _dl_catch_error (char **errstring,
+			    void (*operate) (void *),
+			    void *args)
+     internal_function;
+
+/* Helper function for <dlfcn.h> functions.  Runs the OPERATE function via
+   _dl_catch_error.  Returns zero for success, nonzero for failure; and
+   arranges for `dlerror' to return the error details.
+   ARGS is passed as argument to OPERATE.  */
+extern int _dlerror_run (void (*operate) (void *), void *args)
+     internal_function;
+
 #endif
diff --git a/include/ldsodefs.h b/include/ldsodefs.h
deleted file mode 100644
index f171d4c7ea..0000000000
--- a/include/ldsodefs.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* We must use the appropriate version for the system.  */
-#ifdef HAVE_ELF
-# include <elf/ldsodefs.h>
-#else
-/* We have no dynamic loading.  Define the macros we need here as dummy
-   versions.  */
-# ifndef _LDSODEFS_H
-# define _LDSODEFS_H	1
-
-/* Call a function through a pointer.  */
-# define _CALL_DL_FCT(fctp, args) (*fctp) args
-# define DL_CALL_FCT(fctp, args) (*fctp) args
-
-# endif	/* ldsodefs.h */
-#endif
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
index 8ad4754a3b..ac10f4ea7a 100644
--- a/nss/getXXbyYY_r.c
+++ b/nss/getXXbyYY_r.c
@@ -179,7 +179,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 
   while (no_more == 0)
     {
-      status = _CALL_DL_FCT (fct, (ADD_VARIABLES, resbuf, buffer, buflen,
+      status = DL_CALL_FCT (fct, (ADD_VARIABLES, resbuf, buffer, buflen,
 				   &errno H_ERRNO_VAR));
 
       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c
index 42de65dea2..57bb99f081 100644
--- a/nss/getXXent_r.c
+++ b/nss/getXXent_r.c
@@ -164,7 +164,7 @@ SETFUNC_NAME (STAYOPEN)
   while (! no_more)
     {
       int is_last_nip = nip == last_nip;
-      enum nss_status status = _CALL_DL_FCT (fct, (STAYOPEN_VAR));
+      enum nss_status status = DL_CALL_FCT (fct, (STAYOPEN_VAR));
 
       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
 			    status, 0);
@@ -201,7 +201,7 @@ ENDFUNC_NAME (void)
   while (! no_more)
     {
       /* Ignore status, we force check in __NSS_NEXT.  */
-      _CALL_DL_FCT (fct, ());
+      DL_CALL_FCT (fct, ());
 
       if (nip == last_nip)
 	/* We have processed all services which were used.  */
@@ -245,7 +245,7 @@ INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
     {
       int is_last_nip = nip == last_nip;
 
-      status = _CALL_DL_FCT (fct,
+      status = DL_CALL_FCT (fct,
 			     (resbuf, buffer, buflen, &errno H_ERRNO_VAR));
 
       /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
@@ -277,7 +277,7 @@ INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
 				      (void **) &sfct);
 
 	      if (! no_more)
-		status = _CALL_DL_FCT (sfct, (STAYOPEN_TMPVAR));
+		status = DL_CALL_FCT (sfct, (STAYOPEN_TMPVAR));
 	      else
 		status = NSS_STATUS_NOTFOUND;
 	    }
diff --git a/nss/nsswitch.h b/nss/nsswitch.h
index 9f40a9e46f..c3398d7a7e 100644
--- a/nss/nsswitch.h
+++ b/nss/nsswitch.h
@@ -26,8 +26,7 @@
 #include <nss.h>
 #include <resolv.h>
 #include <search.h>
-#include <ldsodefs.h>
-
+#include <dlfcn.h>
 
 /* Actions performed after lookup finished.  */
 typedef enum
diff --git a/sysdeps/gnu/Makefile b/sysdeps/gnu/Makefile
index 4e814d93cd..4806c0df1d 100644
--- a/sysdeps/gnu/Makefile
+++ b/sysdeps/gnu/Makefile
@@ -45,3 +45,8 @@ endif
 ifeq ($(subdir),misc)
 sysdep_headers += sys/mtio.h
 endif
+
+
+ifeq ($(subdir),dlfcn)
+libdl-routines	+= eval
+endif
diff --git a/sysdeps/gnu/eval.c b/sysdeps/gnu/eval.c
new file mode 100644
index 0000000000..ce452b722c
--- /dev/null
+++ b/sysdeps/gnu/eval.c
@@ -0,0 +1,138 @@
+/* You don't really want to know what this hack is for.
+   Copyright (C) 1996, 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+static void *funcall (char **stringp);
+static void *eval (char **stringp);
+
+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 (p, stringp, 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;
+}
+
+
+void
+_start (void)
+{
+  char *buf = NULL;
+  size_t bufsz = 0;
+
+  while (__getdelim (&buf, &bufsz, '\n', stdin) > 0)
+    {
+      char *p = buf;
+      eval (&p);
+    }
+
+  exit (0);
+}