OSDN Git Service

Initial checkin for ld.so. This is a combination of effort from Manuel Novoa
authorEric Andersen <andersen@codepoet.org>
Mon, 23 Apr 2001 17:43:54 +0000 (17:43 -0000)
committerEric Andersen <andersen@codepoet.org>
Mon, 23 Apr 2001 17:43:54 +0000 (17:43 -0000)
III and me.  I've been working on stripping out arch dependant stuff and
replacing it with generic stuff whenever possible.
 -Erik

58 files changed:
ldso/COPYRIGHT [new file with mode: 0644]
ldso/Makefile [new file with mode: 0644]
ldso/README [new file with mode: 0644]
ldso/config.h [new file with mode: 0644]
ldso/ldso/Makefile [new file with mode: 0644]
ldso/ldso/boot1.c [new file with mode: 0644]
ldso/ldso/dl-elf.c [new file with mode: 0644]
ldso/ldso/dl-hash.c [new file with mode: 0644]
ldso/ldso/hash.c [new file with mode: 0644]
ldso/ldso/hash.h [new file with mode: 0644]
ldso/ldso/i386/dl-sysdep.h [new file with mode: 0644]
ldso/ldso/i386/elfinterp.c [new file with mode: 0644]
ldso/ldso/i386/ld_sysdep.h [new file with mode: 0644]
ldso/ldso/i386/resolve.S [new file with mode: 0644]
ldso/ldso/i386/sysdep.h [new file with mode: 0644]
ldso/ldso/ld-uClibc.c [new file with mode: 0644]
ldso/ldso/ld_hash.h [new file with mode: 0644]
ldso/ldso/ld_string.h [new file with mode: 0644]
ldso/ldso/ld_syscall.h [new file with mode: 0644]
ldso/ldso/ldso.c [new file with mode: 0644]
ldso/ldso/link.h [new file with mode: 0644]
ldso/ldso/linuxelf.h [new file with mode: 0644]
ldso/ldso/m68k/dl-sysdep.h [new file with mode: 0644]
ldso/ldso/m68k/elfinterp.c [new file with mode: 0644]
ldso/ldso/m68k/ld_sysdep.h [new file with mode: 0644]
ldso/ldso/m68k/resolve.S [new file with mode: 0644]
ldso/ldso/m68k/sysdep.h [new file with mode: 0644]
ldso/ldso/readelflib1.c [new file with mode: 0644]
ldso/ldso/sparc/DEFS.h [new file with mode: 0644]
ldso/ldso/sparc/dl-sysdep.h [new file with mode: 0644]
ldso/ldso/sparc/elfinterp.c [new file with mode: 0644]
ldso/ldso/sparc/ld_sysdep.h [new file with mode: 0644]
ldso/ldso/sparc/resolve.S [new file with mode: 0644]
ldso/ldso/sparc/sdiv.S [new file with mode: 0644]
ldso/ldso/sparc/sysdep.h [new file with mode: 0644]
ldso/ldso/sparc/udiv.S [new file with mode: 0644]
ldso/ldso/sparc/umul.S [new file with mode: 0644]
ldso/ldso/sparc/urem.S [new file with mode: 0644]
ldso/ldso/string.h [new file with mode: 0644]
ldso/ldso/syscall.h [new file with mode: 0644]
ldso/ldso/vsprintf.c [new file with mode: 0644]
ldso/libdl/Makefile [new file with mode: 0644]
ldso/libdl/dlfcn.h [new file with mode: 0644]
ldso/libdl/dlib.c [new file with mode: 0644]
ldso/libdl/libdl.c [new file with mode: 0644]
ldso/man/Makefile [new file with mode: 0644]
ldso/man/dlopen.3 [new file with mode: 0644]
ldso/man/ld.so.8 [new file with mode: 0644]
ldso/man/ld.so.texi [new file with mode: 0644]
ldso/man/ldconfig.8 [new file with mode: 0644]
ldso/man/ldd.1 [new file with mode: 0644]
ldso/util/Makefile [new file with mode: 0644]
ldso/util/ldconfig.c [new file with mode: 0644]
ldso/util/ldd.c [new file with mode: 0644]
ldso/util/lddstub.S [new file with mode: 0644]
ldso/util/readelf.c [new file with mode: 0644]
ldso/util/readelf.h [new file with mode: 0644]
ldso/util/readelf2.c [new file with mode: 0644]

diff --git a/ldso/COPYRIGHT b/ldso/COPYRIGHT
new file mode 100644 (file)
index 0000000..fb34248
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, David Engel,
+ * Hongjiu Lu and Mitch D'Souza
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Notice of general intent:
+ *
+ * The linux operating system generally contains large amounts of code
+ * that fall under the GNU General Public License, or GPL for short.
+ * This file contains source code that by it's very nature would always
+ * be linked with an application program, and because of this a GPL
+ * type of copyright on this file would place restrictions upon the
+ * distribution of binary-only commercial software.  Since the goal of
+ * the Linux project as a whole is not to discourage the development and
+ * distribution of commercial software for Linux, this file has been
+ * placed under a more relaxed BSD-style of copyright.
+ *
+ * It is the general understanding of the above contributors that a
+ * program executable linked to a library containing code that falls
+ * under the GPL or GLPL style of license is not subject to the terms of
+ * the GPL or GLPL license if the program executable(s) that are supplied
+ * are linked to a shared library form of the GPL or GLPL library, and as
+ * long as the form of the shared library is such that it is possible for
+ * the end user to modify and rebuild the library and use it in
+ * conjunction with the program executable.
+ */
diff --git a/ldso/Makefile b/ldso/Makefile
new file mode 100644 (file)
index 0000000..23626f5
--- /dev/null
@@ -0,0 +1,13 @@
+include Config.mk
+
+SUBDIRS = util d-link # man
+
+all:
+       set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d ; done
+
+install: all
+       sh instldso.sh
+
+clean:
+       set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
+       -find . -name '*~' | xargs rm -f
diff --git a/ldso/README b/ldso/README
new file mode 100644 (file)
index 0000000..025694e
--- /dev/null
@@ -0,0 +1,860 @@
+
+Apr 20, 2001 -- Manuel Novoa III
+
+Inital port for uClibc from debian ld.so_1.9.11-9.tar.gz.
+
+Removed a.out support.
+
+"make" generates the ld-linux-uclibc.so.1, libdl.so.1, ldd, ldconfig
+       suitable for the target platform.
+
+"make DEVEL=true" generates the same files, but ld-linux-uclibc.so.1 and
+       ldconfig are modified to not conflict with the devel platform system
+       libs.  (This is only of use if TARGET_ARCH == NATIVE_ARCH.)  These
+       modified versions ignore /lib and /usr/lib and look for shared libs
+       only in $(INSTALL_DIR)/lib.  The modified ldconfig writes ld.so.cache
+       in $(INSTALL_DIR)/etc.
+
+The above assumes you've set the DYNAMIC_LINKER to /lib/ld-linux-uclibc.so.1
+in extra/gcc-uClibc/Makefile.
+
+Todo:
+
+Remove unneeded code in util/ldd.c.
+Link against static uClibc instead of using custom routines. ???
+Lots more cleanup... especially the arch-dependent Makefiles.
+
+****************** original ld.so.lsm file **************************
+Begin3
+Title:          Linux shared, dynamic linker and utilities.
+Version:        1.9.11
+Entered-date:   01MAY99
+Description:    This package contains ld.so, ld-linux.so, ldconfig,
+               ldd and libdl.
+Keywords:       dynamic linker, shared library, ld.so, ld-linux.so,
+               ldconfig, ldd, libdl
+Author:         david@ods.com (David Engel)
+Maintained-by:  david@ods.com (David Engel)
+Primary-site:   tsx-11.mit.edu /pub/linux/packages/GCC
+               ld.so-1.9.11.tar.gz
+Alternate-site: sunsite.unc.edu /pub/Linux/GCC
+               ld.so-1.9.11.tar.gz
+Platform:       Linux 2.0.0 or later.
+Copying-policy: Copyrighted but freely distributable.
+End
+*********************************************************************
+                   Original README starts here
+*********************************************************************
+
+This package contains my ELF dynamic linkers (ld-linux.so.1), dynamic
+linker library (libdl.so.1) and utilities (ldconfig and ldd) for Linux.
+
+You need Linux kernel 2.0.0 or later with ELF support compiled in
+(i.e. not loaded as a module) to use this package.
+
+The dynamic linker is used to bootstrap programs and load shared
+libraries at startup.  The dynamic linker library is used to
+dynamically load shared libraries after a program is running.
+Ldconfig is used to automatically update the symbolic links to shared
+libraries and build the cache file used by the dynamic linker.  Ldd is
+used to list the shared libraries used by a program.
+
+Please see the included manual pages for further details.
+
+To install, simply run "sh instldso.sh" as root.  Ready-to-go versions
+of all end-products are provided so nothing should need to be compiled
+or linked.  If you are still using libc5 as your primary development
+library, you should use the "--devfiles" option when running
+instldso.sh to install the file needed to compile with libdl.
+
+ELF versions of gcc, binutils and libc are now required to compile
+everything, including the old, unsupported, a.out dynamic linker.
+Finally, an optimization level of O2 or higher must be used to compile
+ld-linux.so and libdl.so due the use of inline functions.
+
+Notable contributors to this package include Eric Youngdale, Peter
+MacDonald, Hongjiu Lu, Linus Torvalds, Lars Wirzenius, Mitch D'Souza,
+Rik Faith, Andreas Schwab and Adam Richter (not necessarily in that
+order).
+
+###################### IMPORTANT NOTICES #############################
+
+A.OUT SUPPORT:
+
+As of ld.so-1.9.0, the old, a.out dynamic loader is no longer 
+officially supported.  The code is still included and built, but I 
+make no promises that it will work.  I will accept patches for it, 
+but they will not be tested by me.
+
+GLIBC (AKA LIBC6) SUPPORT:
+
+As of ld.so-1.9.0, the main focus of this package is to ease the
+transition to libc6.  No significant, new features are expected to be
+added.  If you need new features, switch to libc6.
+
+Except for libpthread.so, the sonames of the core libraries provided
+with libc6 have been chosen so they do not conflict with those
+provided by libc5 and ld.so.  However, the current plan is not use
+new, nonconflicting sonames for other libraries such as ncurses and
+X11.  This presents two problems.  First, libraries using the same
+soname for both libc5 and libc6 can not be placed in the same
+directory.  Second, the dynamic linkers need to make sure not to load
+a library for the wrong version of libc.
+
+The first problem is easy.  Just move the old, libc5-based libraries
+to new directories (e.g. /lib/libc5-compat, /usr/lib/libc5-compat,
+etc.) and add those directories to /etc/ld.so.conf.  Then install the
+new, libc6-based versions in the standard places.
+
+The second problem is more difficult.  Ideally, the dynamic linkers
+would be changed to perform a complete dependency analysis on every
+library to be loaded to make sure the wrong versions aren't used.
+This approach doesn't seem worth the added complexity, especially
+since we now have symbol versioning for ELF libraries.  Instead a
+simpler approach will be used, at least initially.
+
+Ldconfig has been modified to perform a (currently simple) dependency
+analysis on libraries and to store an indication in /etc/ld.so.cache
+of whether a library is for libc5, libc6 or an unknown libc.  The
+dynamic linkers then only need to make a simple check at run-time to
+make sure they don't load the wrong version of a library.
+
+The dynamic linker for libc5 provided in this package, has already
+been modified to use the new information in /etc/ld.so.cache.  For
+glibc versions 2.0.1 and earlier, the dynamic linker for libc6 needs
+the patch contained in glibc.patch.  You should apply the patch and
+rebuild glibc before using the new ldconfig.
+
+As stated above, the dependency analysis currently done by ldconfig is
+rather simple.  Basically, it looks for the sonames used by the
+various versions of libc, libm and libdl.  For any approach using a
+dependency analysis such as this to work, it is very important that
+shared libraries be built with complete dependency information.  This
+can be done by using the appropriate -l options when running 'gcc
+-shared'.  For example, when building libfoo.so which depends on libc
+and libbar, you should add -lbar and -lc gcc command line.
+
+######################################################################
+
+Changes in version 1.9.11:
+
+       Fixed a bug in ld-linux.so where a reference to an
+       undefined symbol could cause a segfault.
+
+       Added a clarification for LD_PRELOAD to the ld.so manual 
+       page and added a symlink for ld-linux.so (Bug#33123).
+
+       Don't install ldd for Debian except for the m68k arch
+       because glibc 2.1 now includes it (Bug#35458).
+
+Changes in version 1.9.10:
+
+       Changed ldconfig to issue a warning and not overwrite a
+       regular file with a symlink (Bug#30859).
+
+       Changed Debian packaging to conflict with and replace the
+       ldconfig package (Bug#29398).
+
+Changes in version 1.9.9:
+
+       Changed ld-linux.so and libdl.so to match glibc by not
+       allowing user preloads of system libraries into setu/gid
+       binaries unless the library itself is setuid.
+
+       Fixed problems in ld-linux.so on the sparc architecture
+       (Juan Cespedes).
+
+Changes in version 1.9.8:
+
+       Changed ldconfig to allow the expected type for all
+       libraries in a directory to be optionally specified
+       (Mark Phillips).  See the ldconfig man page.
+
+       Changed ldconfig to use the same type names used in the
+       change above when the -p option is used.
+
+Changes in version 1.9.7:
+
+       Changed ldd for m68k to use /lib/ld.so.1 instead of 
+       /lib/ld-linux.so.2.
+
+       Added support for dladdr to libdl.so (Eduard Gode).
+
+       Fixed a small memory leak in libdl.so (Richard Garnish).
+
+       Fixed a bug in ldconfig when the -l option was used on a
+       filename without a '/' in it.
+
+       Updated the man pages (Bug#6404, Bug#9721, Bug#10652, 
+       Bug#13494 and Bug#14127).  They could still use some work.
+
+       No longer install the info page since it's way out of date.
+
+       Fixed minor Debian packaging problems (Bug#13160, 
+       Bug#15577 and Bug#19345).
+
+Changes in version 1.9.6:
+
+       Changed ldd to not use the glibc dynamic linker when run
+       on a libc5-based shared library.
+
+       Added a -q option to ldconfig which causes warnings not
+       to be printed (Bob Tinsley).
+
+       Dropped support for the Debian libdl1-dev package.
+
+       Changed ld-linux.so to be compilable with gcc 2.8.0 (Sven 
+       Verdoolaege)
+
+Changes in version 1.9.5:
+
+       Fixed a bug in ldd where ld-linux.so.2 was not called
+       correctly when run on shared libraries.
+
+       Fixed a problem in the previous version where some
+       Makefiles were not architecture independent.
+
+Changes in version 1.9.4:
+
+       Fixed a bug in ld.so introduced in the previous version
+       which broke preloads.
+
+       Turned a.out support back on by default, at least for the
+       time being.  There are no promises to keep it.
+
+Changes in version 1.9.3:
+
+       Fixed buffer overflow bugs in ld-linux.so and ld.so.
+
+       Changed the README file a little to clarify a couple of
+       things.
+
+       Changed ldconfig to chroot to the specified directory when
+       the new -r option is used (Bob Tinsley).
+
+Changes in version 1.9.2:
+
+       Removed /usr/local/lib from the default /etc/ld.so.conf
+       for Debian (Bug#8181).
+
+       Changed ldconfig to be 64-bit clean (H.J. Lu).
+
+Changes in version 1.9.1:
+
+       Changed ldconfig to try to determine which libc a
+       library is for even if it doesn't have an soname.
+
+       Fixed a bug in ldconfig where an older library using
+       the glibc naming convention would be used instead of
+       a newer library.
+
+       Changed to ld-linux.so and libdl.so to not require the 
+       libc5 headers in order to compile.
+
+       Changed ldconfig and ldd to be compilable with either
+       libc5 or libc6.
+
+Changes in version 1.9.0:
+
+       Changed to not build the old, a.out dynamic loader by
+       default.
+
+       Changed instldso.sh to require the --force option to
+       make sure users read the README file.
+
+       Changed instldso.sh to not install the libdl.so
+       development files unless the --devfiles option is used.
+
+       Changed instldso.sh to not strip binaries and libraries
+       if the --no-strip option is used.
+
+       Changed the Debian packaging to put the development files 
+       which conflict with glibc in a new libdl1-dev package.
+
+       Changed ldd to use the glibc dynamic linker, if it is
+       available, when run on a shared library.
+
+       Changed ld-linux.so to print the load addresses of
+       libraries, ala glibc, when run by ldd.
+
+       Changed ld-linux.so to allow the libraries listed in 
+       LD_PRELOAD to be separated by white space in addition to 
+       colons.
+
+       Changed ld-linux.so to load the libraries listed in 
+       LD_PRELOAD for setu/gid programs as long as they can be 
+       loaded securely.
+
+       Changed ldconfig to update the symlinks for the dynamic
+       linkers.
+
+       Changed ldconfig to try to determine if an ELF library is
+       intended for libc5 or libc6 and save the infomation in the
+       cache.  The mechanism used is rather simplistic and may
+       need to be enhanced.
+
+       Changed ldconfig to print the type of ELF library when
+       printing the cache.
+
+       Changed ld-linux.so to only load ELF shared libraries for
+       use with libc5 or an unknown libc.
+
+Changes in version 1.8.10:
+
+       Fixed a bug in ldconfig where a symlink could be used
+       instead of a regular file.
+
+       Fixed a Debian packaging problem for the sparc 
+       architecture.
+
+Changes in version 1.8.9:
+
+       Changed ldconfig to only cache the symlinks it creates.
+       This make the behavior of the dynamic linkers consistent
+       with how they would behave if a cache was not used.
+
+       Changed ldconfig to cache the symlinks that it finds but
+       use the name of the symlink as the soname instead of the 
+       actual soname.
+
+Changes in version 1.8.8:
+
+       Minor documentation updates to reflect recent changes.
+
+       Changed ld.so and ld-linux.so to perform more complete
+       validation on ld.so.cache before using it.
+
+       Changed ldconfig to accept libraries with inconsistent
+       sonames since glibc is going to use them.  A warning is
+       still printed in debug mode.
+
+       Changed the install script to not strip _dl_debug_state
+       from ld-linux.so since gdb needs it.
+
+       More sparc fixes (Derrick Brashear).
+
+       Changed ldconfig to not issue a warning when a linker
+       script disguised as a shared library is found.
+
+       Fixed a bug in ld-linux.so where some registers were 
+       not preserved on the first call to a function causing 
+       problems for non-C-like languages (Tim Renouf).
+
+       Fixed a bug in ld-linux.so where global variables were 
+       not always mapped correctly across dynamically loaded 
+       libraries (Mikihiko Nakao).
+
+       Converted to new Debian source packaging format (Shaya
+       Potter).
+
+Changes in version 1.8.6/7:
+
+       Never released as some unofficial patches used these
+       version numbers.
+
+Changes in version 1.8.5:
+
+       Fixed a bug in ld.so introduced in the previous changes.
+
+Changes in version 1.8.4:
+
+       Changed ldconfig to completely ignore symbolic links.
+
+       Changed ldconfig to issue the warning concerning an
+       inconsistent soname in non-verbose mode.
+
+       Changed ld-linux.so back to not keep ld.so.cache mapped
+       at all times.
+
+       Changed Debian packaging to compress man pages, strip all
+       binaries (Bug#5125) and include a shlibs file.
+
+Changes in version 1.8.3:
+
+       Changed ld-linux.so to process LD_PRELOAD before
+       /etc/ld.so.preload.
+
+       Fixed a Debian packaging problem where libdl might not
+       be available if other packages were upgraded at the same
+       time (Debian Bug#4728).
+
+       Changed ldd to always exit with status 1 if any errors
+       occur (Debian Bug#4188).
+
+       Fixed some minor problems in instldso.sh (Mike Castle and
+       Wolfgang Franke).
+
+       Changed ldconfig to issue a warning in verbose mode when 
+       skipping a library because the soname doesn't match.
+
+       More sparc fixes (Miguel de Icaza).
+
+       Don't link with -N when building ld.so (Alan Modra).
+
+       Changed ld-linux.so to better support position-dependant
+       libraries (NIIBE Yutaka).
+
+Changes in version 1.8.2:
+
+       Added a texinfo file for ld.so and libdl (Michael 
+       Deutschmann).
+
+       Minor sparc and installation changes (Elliot Lee).
+
+       Added multiple architecture support for Debian (Leland
+       Lucius).
+
+       Changed libdl to better support RTLD_NEXT (Eric 
+       Youngdale).  Note: the exact meaning of ETLD_NEXT is 
+       still not clear in all cases.
+
+       Removed some libc dependencies from libdl.  Still need
+       to remove malloc and free.
+
+Changes in version 1.8.1:
+
+       Changed ld.so to be compiled as ELF.  This also means
+       that ELF support is now required.  A.out support is 
+       still optional.
+
+       Changed ld-linux.so and libdl.so to use the rpath in the 
+       executable instead of in the invoking shared library.
+
+       More m68k fixes (Andreas Schwab).
+
+       Various sparc fixes (Miguel de Icaza).
+
+       Changed ldcnnfig to ignore libraries ending in '~'.
+
+       Changed ldconfig to allow alternative conf and cache 
+       files to be specified on the command-line.
+
+       Changed libdl.so to work when dlsym is passed a NULL
+       handle pointer.
+
+Changes in version 1.8.0:
+
+       Changed ld-linux.so to be more liberal when checking to
+       see if a library is already loaded.  This should avoid
+       the duplicate loading problem for programs linkeed with
+       the -rpath option.
+
+       Various m68k fixes (Andreas Schwab).
+
+       Changed ld.so to only use LD_AOUT_LIBRARY_PATH and
+       LD_AOUT_PRELOAD and ld-linux.so to only use 
+       LD_LIBRARY_PATH and LD_PRELOAD.  LD_ELF_LIBRARY_PATH
+       and LD_ELF_PRELOAD are no longer supported.
+
+       Changed ld-linux.so to allow debugging of shared and
+       dynamically loaded libraries (H.J. Lu, Andreas Schwab).
+
+       Changed ld-linux.so to preload ELF shared libraries 
+       listed in /etc/ld.so.preload.  This allows secure 
+       preloads, even for setuid/setgid programs.
+
+       Changed ld-linux.so to keep ld.so.cache mapped at all
+       times.
+
+       Changed ldconfig to allow #-style comments in ld.so.conf.
+
+       Removed various compiler warnings (Richard Sladkey and
+       David Engel).
+
+       Changed ldd to work on ELF shared libraries.  This may
+       need a little more work.
+
+Changes in version 1.7.14:
+
+       Changed ldconfig to recognize ELF shared libraries
+       generated by post-2.6 versions of ld (Andreas Schwab).
+
+       Changed ldconfig to not remove stale links that do not
+       have a version number since they may be needed by ld.
+
+Changes in version 1.7.13:
+
+       Fixed a problem in ld-linux.so where a program linked
+       with a shared library that was not used could result in
+       a segmentation fault (H.J. Lu).
+
+Changes in version 1.7.12:
+
+       Fixed a problem in libdl.so where the wrong library
+       could be marked as global when RTLD_GLOBAL was used
+       (Lars Heete).
+
+       Installed dlfcn.h with libdl.so instead of requiring
+       it to be supplied with libc.
+
+       Removed support for libldso.a since it was nearly
+       impossible to use anyway.
+
+       Changed ldd to detect when the program being checked
+       exited abnormally.
+
+Changes in version 1.7.11:
+
+       Changed ld.so and ld-linux.so to delete all variations
+       of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs,
+       This makes it harder for broken set[ug]id programs to be
+       compromised.
+
+       Fixed a problem in libdl.so where dlsym would not accept
+       the handle returned from dlopen(0, *).
+
+Changes in version 1.7.10:
+
+       Changed ld-linux.so and libdl.so to support RTLD_GLOBAL
+       (Eric Youngdale).
+
+Changes in version 1.7.9:
+
+       Fixed a problem in ld-linux.so in detecting when the 
+       new user/group information is provided by the kernel.
+
+       Fixed a problem in ld-linux.so where a buffer could be
+       overflowed if a large number of libraries were loaded
+       (Thomas Moore).
+
+Changes in version 1.7.8:
+
+       Changed the Makefiles and install scripts to support 
+       a.out- and ELF-only configurations.
+
+       Changed ld-linux.so to use the user/group information
+       provided by linux 1.3.23+ instead of making syscalls
+       to get it.
+
+       Changed libdl.so to support RTLD_NEXT (Glenn Fowler).
+
+       Changed libdl.so to only execute the fini sections
+       instead of completely closing libraries at exit (Glenn
+       Fowler).
+
+       Changed ld.so and ld-linux.so to print the required
+       cache version when a mismatch is detected.
+
+       Changed ld-linux.so to not require on /dev/zero (Ralph
+       Loader).
+
+       Minor m68k cleanups (Andreas Schwab).
+
+Changes in version 1.7.7:
+
+       Fixed problems compiling with recent 1.3.x kernels.
+
+       Changed ld-linux.so to not use MAP_DENYWRITE until the
+       permission issue regarding it is resolved.
+
+Changes in version 1.7.6:
+
+       Fixed a bug in ld-linux.so dealing with a zero-length
+       LD_{ELF_}PRELOAD.
+
+       Changed ld.so and ld-linux.so to truncate all variations
+       of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs.
+
+Changes in version 1.7.5:
+
+       Changed ldconfig to recognize libraries without any
+       version number (eg. libXYZ.so).
+
+       Changed ldconfig to not generate a corrupt cache when
+       the disk is full or other write errors occur.
+
+       Changed ld-linux.so to map files with MAP_DENYWRITE to
+       keep them from being changed while the file is in use
+       (Rick Sladkey).
+
+       Changed libdl to not overwrite the scope pointer of a 
+       library if it was already loaded (H.J. Lu).
+
+       Changed ld-linux.so so gdb can be used on constructors
+       (Eric Youngdale).
+
+       Changed ldconfig to ignore ELF libraries where the soname
+       does not match the file name on the assumption that it is
+       a used at compile-time (eg. libcurses.so -> libncruses.so).
+
+Changes in version 1.7.4:
+
+       Changed ld-linux.so and libdl to use the appropriate
+       rpaths when searching for shared libraries (Eric
+       Youngdale).
+
+       Changed ld-linux.so to search rpath before using the
+       cache.  This more closely conforms to the IBCS standard.
+
+Changes in version 1.7.3:
+
+       Changed ld-linux.so to only print a library name the
+       first time it is loaded when run from ldd.
+
+       Fixed a bug in ldconfig where an invalid cache could be
+       generated if a directory was specified multiple times in
+       ld.so.conf.
+
+       Changed ld-linux.so so it will return the address of a
+       weak symbol when called from dlsym in libdl (Eric 
+       Youngdale.
+
+Changes in version 1.7.2:
+
+       Changed libdl.so again to fix the undefined foobar
+       problem.
+
+Changes in version 1.7.1:
+
+       Changed libdl so it will compile at optimization level
+       O3 or higher.
+
+       Changed ldconfig to always create the cache file with 
+       mode 644.
+
+       Changed ldconfig to not ingore valid symlinks.
+
+       Changed ldconfig to use the library name as the soname 
+       for ELF libraries that do not have an soname entry.
+
+       Changed ld-linux.so to print the actual, requested library
+       name at the time it is loaded instead of trying to figure
+       it out after the fact.
+
+Changes in version 1.7.0:
+
+       Changed ldconfig to read the actual soname from the image
+       for ELF libraries and make it available to ld-linux.so.  
+       The soname for DLL libraries is still determined by
+       truncating the minor numbers from the image file name.
+
+       Changed ldconfig to no longer support the undocumented
+       sort options.
+
+       Changed ld.so to require a valid cache to find libraries
+       in directories specified in ld.so.conf.  /usr/lib and /lib
+       are still searched as a last resort.  Ld-linux.so already
+       operated this way.
+
+       Fixed a bug in libldso.a where the arguments to
+       shared_loader were not parsed correctly (Wolfram Gloger).
+
+       Added support for RELA-style relocations under Linux/68k
+       (Andreas Schwab).
+
+       Changed ld-linux.so to only map the cache once for all
+       libraries instead of individually for each library.
+
+       Changed ld-linux.so continue searching the cache instead of
+       giving up when failing to load the first entry found.
+
+       Changed ld-linux.so to produce output similar to ld.so when
+       run from ldd or when errors occur.
+
+Changes in version 1.6.7:
+
+       Changed the install scripts to make sure that ld.so and
+       ld-linux.so are always usable.
+
+       Added support for Linux/Sparc (Eric Youngdale).
+
+       Added support for Linux/68k (Andreas Schwab).
+
+       Fixed various bugs in ld-linux.so dealing with closing
+       files, unmapping memory, dereferencing NULL pointers and 
+       printing library names (David Engel, Eric Youngdale and 
+       Andreas Schwab).
+
+       Replaced the manual page for libdl with a freely
+       distributable one (Adam Richter).
+
+       Fixed a bug in ld-linux.so where LD_LIBRARY_PATH and
+       LD_PRELOAD were not cleared for setuid/setgid programs.
+
+       Fixed a bug in libdl where dlsym would not return the
+       correct address of a symbol if it was redefined in another
+       library (Oleg Kibirev).
+
+       Changed ld-linux.so to use the following order to search 
+       for libraries:  LD_{ELF_}LIBRARY_PATH, ld.so.cache, rpath, 
+       /usr/lib and /lib.
+
+       Changed ld-linux.so to not needlessly allocate memory when
+       using ld.so.cache.
+
+Changes in version 1.6.6:
+
+       Changed ldconfig to not warn about removing stale links
+       unless the -v option is specified.
+
+       Added manual pages for libdl (from FreeBSD/Sun)
+
+       Fixed a bug in ld.so dealing with preloading of objects
+       generated by recent versions of ld (Mitch D'Souza).
+
+       Fixed bugs in ldd where some errors were either not
+       detected or not printed.
+
+       Fixed a bug in ld-linux.so where the trailing nul in a
+       library name was not being copied (Owen Taylor).
+
+Changes in version 1.6.5:
+
+       Changed ldconfig to remove stale symbolic links.
+
+       Added debug hooks in ld-linux.so and libdl.so to be used 
+       by a future version of gdb (Eric Youngdale).
+
+Changes in version 1.6.4:
+
+       Change ld-linux.so to print on stdout instead of stderr
+       when run from ldd.
+
+       Added support for Debian GNU/Linux packaging.
+
+Changes in version 1.6.3:
+
+       Fixed a bug in libdl when closing a library (H.J. Lu).
+
+Changes in version 1.6.2:
+
+       Changed the error message printed by ldd when a file is
+       not a.out or ELF.  It used to only list a.out formats.
+
+       Changed ldconfig to no longer cache and set up links for
+       ld-linux.so.
+
+       Changed ld-linux.so and libdl to not conflict with upcoming
+       changes in kernel header files.
+
+       Changed ld-linux.so to not print preloaded libraries.
+
+Changes in version 1.6.1:
+
+       Updated the installation script.
+
+       Changed ld.so and ld-linux.so to look for LD_AOUT_PRELOAD
+       and LD_ELF_PRELOAD, respectively, before LD_PRELOAD.
+
+       Changed ld.so and ld-linux.so to use LD_AOUT_LIBRARY_PATH
+       and LD_ELF_LIBRARY_PATH, respectively, instead of
+       AOUT_LD_LIBRARY_PATH and ELF_LD_LIBRARY_PATH.
+
+Changes in version 1.6.0:
+
+       Changed ldconfig to process libraries which do not have
+       a minor version or patch level number.
+
+       Incorporated ld-linux.so and libdl.so.
+
+       Changed ld.so and ld-linux.so to not miss entries in the
+       cache when the fully qualified library is requested.
+
+       Changed ldconfig to use stdout instead of stderr when
+       printing the cache.
+
+Changes in version 1.5.3:
+
+       LD_PRELOAD enhancements (Tristan Gigold).
+
+       LD_PRELOAD patch for linux-68k (Andreas Schwab).
+
+Changes in version 1.5.2:
+
+       More ELF changes (Mitch D'Souza).
+
+       Changed ldconfig to also update the link for ld-linux.so.
+
+Changes in version 1.5.1:
+
+       More ELF and LD_PRELOAD changes (Mitch D'Souza).
+
+Changes in version 1.5.0:
+
+       Chnaged all executables to QMAGIC (Mitch D'Souza and Rick
+       Sladkey).
+
+       Added preliminary support for ELF to ldd and ldconfig (Eric 
+       Youndale and H.J. Lu).
+
+       Added support for LD_PRELOAD to ld.so (Mitch D'Souza).
+
+       Removed the "advertising" clause from the copyright notices
+       in all source files.
+
+Changes in version 1.4.4:
+
+       Changed ldconfig to support QMAGIC libraries.
+
+       Fixed a bug in ld.so where some of the error messages had
+       transposed arguments.
+
+Changes in version 1.4.3:
+
+       Fixed an obscure bug in ld.so where an index was not being
+       incremented when a library was not found using the cache.
+
+Changes in version 1.4.2:
+
+       Changed ldconfig to issue a warning and continue instead
+       of an error and exiting when a link can't be updated.  
+       This is useful when some libraries are imported on read-
+       only file systems, such as an NFS mounted /usr.
+
+       Changed ld.so to be more robust in searching for libraries.
+       A library is not considered found unless it can actually be
+       loaded.  If a library is not found using the cache, the
+       standard directories are searched as in pre-cache versions.
+
+Changes in version 1.4.1:
+
+       Fixed minor Makefile problems.
+
+       Added support for linux-68k.
+
+       Fixed a bug in ld.so where libraries with absolute paths
+       were not handled correctly.
+
+       Changed ld.so to ignore the directory in the names of
+       shared libraries by default.  This allows older libraries
+       with absolute paths, such as the XView libraries, to take
+       advantage of the cache support.
+
+       Added a minimal usage message to ldconfig.
+
+Changes in version 1.4:
+
+       Fixed bug in ld.so where minor version numbers were not
+       reported correctly when a minor version incompatibility
+       was found.
+
+       Fixed bug in ldconfig where libraries with subversion
+       numbers greater than 9 were not compared correctly.
+
+       Added Mitch D'Souza's support for suppressing warning
+       messages from ld.so about minor version incompatibilities.
+
+       Added Mitch D'Souza's support for using a cache to speed
+       up searching for libraries in the standard directories.
+
+       Added Mitch D'Souza's support for a debugging version of
+       ld.so.  Link with -lldso if you think you are experiencing
+       dynamic linker problems.
+
+Changes in version 1.3:
+
+       Added support for libraries using absolute pathnames.  If I
+       had known that the XView libraries used them, I would have
+       added this earlier.
+
+       Fixed a bug handling old libraries using a pathname beginning
+       with '/' or '/lib/'.
+
+Changes in version 1.2a:
+
+       Fixed a minor bug in ldd which caused all files, specifically
+       scripts, to be recognized as binaries.  Thanks to Olaf Flebbe
+       for reporting it.
+
+David Engel
+david@sw.ods.com
diff --git a/ldso/config.h b/ldso/config.h
new file mode 100644 (file)
index 0000000..1d1429d
--- /dev/null
@@ -0,0 +1,59 @@
+#ifdef DEBUG
+#  define LDSO_IMAGE "../ld-so/ld.so"
+#  define LDSO_CONF  "../util/ld.so.conf"
+#  define LDSO_CACHE "../util/ld.so.cache"
+#  define LDSO_PRELOAD "../util/ld.so.preload"
+#  define LDDSTUB    "../util/lddstub"
+#elif UCLIBC_DEVEL
+#  define LDSO_IMAGE UCLIBC_INSTALL_DIR"/lib/ld.so"
+#  define LDSO_CONF  UCLIBC_INSTALL_DIR"/etc/ld.so.conf"
+#  define LDSO_CACHE UCLIBC_INSTALL_DIR"/etc/ld.so.cache"
+#  define LDSO_PRELOAD UCLIBC_INSTALL_DIR"/etc/ld.so.preload"
+#  define LDDSTUB    UCLIBC_INSTALL_DIR"/lib/lddstub"
+#else
+#  define LDSO_IMAGE "/lib/ld.so"
+#  define LDSO_CONF  "/etc/ld.so.conf"
+#  define LDSO_CACHE "/etc/ld.so.cache"
+#  define LDSO_PRELOAD "/etc/ld.so.preload"
+#  define LDDSTUB    "/usr/lib/lddstub"
+#endif
+
+#define LDD_ARGV0    "__LDD_ARGV0"
+#define DIR_SEP      ":, \t\n"
+#define MAX_DIRS     32
+
+typedef void (*loadptr)(int func, ...);
+typedef void (*callbackptr)(int ver, int nlibs, char **libs, 
+               int nmods, char **mods);
+
+#define CALLBACK_VER 1
+
+#define LIB_ANY             -1
+#define LIB_DLL       0
+#define LIB_ELF       1
+#define LIB_ELF_LIBC5 2
+#define LIB_ELF_LIBC6 3
+#define LIB_ELF64     0x80
+
+#define FUNC_VERS    0
+#define FUNC_LDD     1
+#define FUNC_LINK    2
+#define FUNC_LINK_AND_CALLBACK 3
+
+#define LDSO_CACHE_MAGIC "ld.so-"
+#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
+#define LDSO_CACHE_VER "1.7.0"
+#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
+
+typedef struct {
+       char magic   [LDSO_CACHE_MAGIC_LEN];
+       char version [LDSO_CACHE_VER_LEN];
+       int nlibs;
+} header_t;
+
+typedef struct {
+       int flags;
+       int sooffset;
+       int liboffset;
+} libentry_t;
+
diff --git a/ldso/ldso/Makefile b/ldso/ldso/Makefile
new file mode 100644 (file)
index 0000000..80f0643
--- /dev/null
@@ -0,0 +1,39 @@
+TOPDIR=../../
+include $(TOPDIR)Rules.mak
+include $(TOPDIR)/ld.so-1/Config.mk
+
+DIRS = $(TARGET_ARCH) libdl
+
+CFLAGS += -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -DUSE_CACHE #-fPIC -D__PIC__ #-funroll-loops
+
+CSRC= boot1.c hash.c readelflib1.c vsprintf.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+OBJS=$(COBJS)
+
+DLINKER = ld-linux-uclibc.so
+
+ELF_LDFLAGS=--shared # using GNU ld
+
+ifneq ($(DIRS),)
+lib realclean clean::
+       @set -e; for i in $(DIRS); do \
+         echo making $@ in $$i; \
+         $(MAKE) -C $$i $@; \
+       done;
+endif
+
+lib:: $(OBJS)
+       $(LD) -e _dl_boot $(ELF_LDFLAGS) -o $(DLINKER).$(LDSO_VMAJOR) \
+         -soname $(DLINKER).$(LDSO_VMAJOR) *.o
+
+$(COBJS): %.o : %.c
+       $(CC) -I. -I./$(TARGET_ARCH) $(CFLAGS) -c $< -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+realclean::
+       $(RM) -f .depend $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~
+
+clean::
+       $(RM) -f $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~
+
diff --git a/ldso/ldso/boot1.c b/ldso/ldso/boot1.c
new file mode 100644 (file)
index 0000000..6b0b864
--- /dev/null
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* Program to load an ELF binary on a linux system, and run it.
+ * References to symbols in sharable libraries can be resolved by
+ * an ELF sharable library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+/*
+ * The main trick with this program is that initially, we ourselves are not
+ * dynamicly linked.  This means that we cannot access any global variables
+ * since the GOT is initialized by the linker assuming a virtual address of 0,
+ * and we cannot call any functions since the PLT is not initialized at all
+ * (it will tend to want to call the dynamic linker
+ *
+ * There are further restrictions - we cannot use large switch statements,
+ * since the compiler generates tables of addresses and jumps through them.
+ * We can use inline functions, because these do not transfer control to
+ * a new address, but they must be static so that they are not exported
+ * from the modules.  We cannot use normal syscall stubs, because these
+ * all reference the errno global variable which is not yet initialized.
+ * We can use all of the local stack variables that we want, since these
+ * are all referenced to %ebp or %esp.
+ *
+ * Life is further complicated by the fact that initially we do not want
+ * to do a complete dynamic linking.  We want to allow the user to supply
+ * new functions replacing some of the library versions, and until we have
+ * the list of modules that we should search set up, we do not want to do
+ * any of this.  Thus I have chosen to only perform the relocations for
+ * variables that start with "_dl_" since ANSI specifies that the user is
+ * not supposed to redefine any of these variables.
+ *
+ * Fortunately, the linker itself leaves a few clues lying around, and
+ * when the kernel starts the image, there are a few further clues.
+ * First of all, there is information buried on the stack that the kernel
+ * leaves, which includes information about the load address that the
+ * program interpreter was loaded at, the number of sections, the address
+ * the application was loaded at and so forth.  Here this information
+ * is stored in the array dl_info, and the indicies are taken from the
+ * file /usr/include/sys/auxv.h on any SVr4 system.
+ *
+ * The linker itself leaves a pointer to the .dynamic section in the first
+ * slot of the GOT, and as it turns out, %ebx points to ghe GOT when
+ * you are using PIC code, so we just dereference this to get the address
+ * of the dynamic sections.
+ *
+ * Typically you must load all text pages as writable so that dynamic linking
+ * can succeed.  The kernel under SVr4 loads these as R/O, so we must call
+ * mprotect to change the protections.  Once we are done, we should set these
+ * back again, so the desired behavior is achieved.  Under linux there is
+ * currently no mprotect function in the distribution kernel (although
+ * someone has alpha patches), so for now everything is loaded writable.
+ *
+ * We do not have access to malloc and friends at the initial stages of dynamic
+ * linking, and it would be handy to have some scratchpad memory available
+ * for use as we set things up.  It is a bit of a kluge, but we mmap /dev/zero
+ * to get one page of scratchpad.  A simpleminded _dl_malloc is provided so
+ * that we have some memory that can be used for this purpose.  Typically
+ * we would not want to use the same memory pool as malloc anyway - the user
+ * might want to redefine malloc for example.
+ *
+ * Our first task is to perform a minimal linking so that we can call other
+ * portions of the dynamic linker.  Once we have done this, we then build
+ * the list of modules that the application requires, using LD_LIBRARY_PATH
+ * if this is not a suid program (/usr/lib otherwise).  Once this is done,
+ * we can do the dynamic linking as required (and we must omit the things
+ * we did to get the dynamic linker up and running in the first place.
+ * After we have done this, we just have a few housekeeping chores and we
+ * can transfer control to the user's application.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+static char * _dl_malloc_addr, *_dl_mmap_zero;
+char * _dl_library_path = 0; /* Where we look for libraries */
+char *_dl_preload = 0; /* Things to be loaded before the libs. */
+char *_dl_progname = "/lib/ld-linux-uclibc.so.1";
+static char * _dl_not_lazy = 0;
+static char * _dl_warn = 0; /* Used by ldd */
+static char * _dl_trace_loaded_objects = 0;
+static int (*_dl_elf_main)(int, char **, char**);
+
+static int (*_dl_elf_init)(void);
+
+void * (*_dl_malloc_function)(int size) = NULL;
+
+struct r_debug * _dl_debug_addr = NULL;
+
+unsigned int * _dl_brkp; 
+
+unsigned int * _dl_envp;
+
+#define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE))
+/*
+ * Make sure that the malloc buffer is aligned on 4 byte boundary.  For 64 bit
+ * platforms we may need to increase this to 8, but this is good enough for
+ * now.  This is typically called after DL_MALLOC.
+ */
+#define REALIGN() malloc_buffer = (char *) (((unsigned int) malloc_buffer + 3) & ~(3))
+
+
+
+#define ELF_HASH(RESULT,NAME) { \
+  unsigned long hash = 0; \
+    unsigned long tmp;  \
+  char * name = NAME; \
+  while (*name){  \
+    hash = (hash << 4) + *name++; \
+    if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; \
+    hash &= ~tmp; \
+  } \
+  RESULT = hash; \
+}
+extern int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct elf32_rel ELF_RELOC;
+#endif
+
+/*
+ * This stub function is used by some debuggers.  The idea is that they
+ * can set an internal breakpoint on it, so that we are notified when the
+ * address mapping is changed in some way.
+ */
+void _dl_debug_state()
+{
+  return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+  unsigned int argc;
+  char ** argv, ** envp;
+  int status;
+
+  unsigned int load_addr;
+  unsigned int * got;
+  unsigned int * aux_dat;
+  int goof = 0;
+  struct elfhdr * header;
+  struct elf_resolve * tpnt;
+  struct dyn_elf * rpnt;
+  struct elf_resolve * app_tpnt;
+  unsigned int brk_addr;
+  unsigned int dl_data[AT_EGID+1];
+  unsigned char * malloc_buffer, *mmap_zero;
+  int (*_dl_atexit)(void *);
+  int * lpnt;
+  struct dynamic * dpnt;
+  unsigned int *hash_addr;
+  struct r_debug * debug_addr;
+  unsigned int *chains;
+  int indx;
+  int _dl_secure;
+
+  /* First obtain the information on the stack that tells us more about
+     what binary is loaded, where it is loaded, etc, etc */
+
+  GET_ARGV(aux_dat, args);
+  argc = *(aux_dat - 1);
+  argv = (char **) aux_dat;
+  aux_dat += argc;  /* Skip over the argv pointers */
+  aux_dat++;  /* Skip over NULL at end of argv */
+  envp = (char **) aux_dat;
+  while(*aux_dat) aux_dat++;  /* Skip over the envp pointers */
+  aux_dat++;  /* Skip over NULL at end of envp */
+  dl_data[AT_UID] = -1; /* check later to see if it is changed */
+  while(*aux_dat)
+    {
+      unsigned int * ad1;
+      ad1 = aux_dat + 1;
+      if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+      aux_dat += 2;
+    }
+
+  /* Next, locate the GOT */
+
+  load_addr = dl_data[AT_BASE];
+
+  GET_GOT(got);
+  dpnt = (struct dynamic *) (*got + load_addr);
+  /* OK, time for another hack.  Now call mmap to get a page of writable
+     memory that can be used for a temporary malloc.  We do not know brk
+     yet, so we cannot use real malloc. */
+
+  {
+    /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+    int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+    /* See if we need to relocate this address */
+    mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+                            PROT_READ | PROT_WRITE, 
+                            MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+    if(_dl_mmap_check_error(mmap_zero)) {
+       SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n");
+       _dl_exit(13);
+    }
+  }
+
+  tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (tpnt, 0, sizeof (*tpnt));
+  app_tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (app_tpnt, 0, sizeof (*app_tpnt));
+
+  /*
+   * This is used by gdb to locate the chain of shared libraries that are currently loaded.
+   */
+  debug_addr = DL_MALLOC(sizeof(struct r_debug));
+  REALIGN();
+  _dl_memset (debug_addr, 0, sizeof (*debug_addr));
+
+  /* OK, that was easy.  Next scan the DYNAMIC section of the image.
+     We are only doing ourself right now - we will have to do the rest later */
+
+  while(dpnt->d_tag)
+    {
+      tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+      if(dpnt->d_tag == DT_TEXTREL ||
+        SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+      dpnt++;
+    }
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+    
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+      if(ppnt->p_type == PT_DYNAMIC) {
+       dpnt = (struct dynamic *) ppnt->p_vaddr;
+       while(dpnt->d_tag)
+         {
+           if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+           app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+           if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+           if(dpnt->d_tag == DT_TEXTREL ||
+              SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1;
+           dpnt++;
+         }
+      }
+  }
+
+  /* Get some more of the information that we will need to dynamicly link
+     this module to itself */
+
+  hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr);
+  tpnt->nbucket = *hash_addr++;
+  tpnt->nchain = *hash_addr++;
+  tpnt->elf_buckets = hash_addr;
+  hash_addr += tpnt->nbucket;
+  chains = hash_addr;
+
+  /* Ugly, ugly.  We need to call mprotect to change the protection of
+     the text pages so that we can do the dynamic linking.  We can set the
+     protection back again once we are done */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    /* First cover the shared library/dynamic linker. */
+    if(tpnt->dynamic_info[DT_TEXTREL]) {
+      header = (struct elfhdr *) dl_data[AT_BASE];         
+      ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+      for(i=0; i<header->e_phnum ; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+               _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+                             (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                             PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+    
+    /* Now cover the application program. */
+    if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+      ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+      for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+         _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+                      (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                      PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+  }
+
+  /* OK, now do the relocations.  We do not do a lazy binding here, so
+   that once we are done, we have considerably more flexibility. */
+
+  goof = 0;
+  for(indx=0; indx < 2; indx++)
+    {
+      int i;
+      ELF_RELOC * rpnt;
+      unsigned int * reloc_addr;
+      unsigned int symbol_addr;
+      int symtab_index;
+      unsigned int rel_addr, rel_size;
+
+  
+#ifdef ELF_USES_RELOCA
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+      if(!rel_addr) continue;
+
+      /* Now parse the relocation information */
+      rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+      for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+       reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr = 0;
+       if(symtab_index) {
+         char * strtab;
+         struct elf32_sym * symtab;
+
+         symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+         /* We only do a partial dynamic linking right now.  The user
+            is not supposed to redefine any symbols that start with
+            a '_', so we can do this with confidence. */
+
+         if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+         symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+         if(!symbol_addr) {
+           /*
+            * This will segfault - you cannot call a function until
+            * we have finished the relocations.
+            */
+           SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+           SEND_STDERR(strtab + symtab[symtab_index].st_name);
+           SEND_STDERR(" undefined.\n");
+           goof++;
+         }
+       }
+       /*
+        * Use this machine-specific macro to perform the actual relocation.
+        */
+       PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+      }
+    }
+
+  if (goof)    _dl_exit(14);
+
+  /* OK, at this point we have a crude malloc capability.  Start to build
+     the tables of the modules that are required for this beast to run.
+     We start with the basic executable, and then go from there.  Eventually
+     we will run across ourself, and we will need to properly deal with that
+     as well. */
+
+  _dl_malloc_addr = malloc_buffer;
+
+  _dl_mmap_zero = mmap_zero;
+/*  tpnt = _dl_malloc(sizeof(struct elf_resolve)); */
+
+/* Now we have done the mandatory linking of some things.  We are now
+   free to start using global variables, since these things have all been
+   fixed up by now.  Still no function calls outside of this library ,
+   since the dynamic resolver is not yet ready. */
+
+  lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr);
+  INIT_GOT(lpnt, tpnt);
+
+  /* OK, this was a big step, now we need to scan all of the user images
+     and load them properly. */
+
+  tpnt->next = 0;
+  tpnt->libname = 0;
+  tpnt->libtype = program_interpreter;
+
+  { struct elfhdr * epnt;
+    struct elf_phdr * ppnt;
+    int i;
+
+    epnt = (struct elfhdr *) dl_data[AT_BASE];
+    tpnt->n_phent = epnt->e_phnum;
+    tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff);
+    for(i=0;i < epnt->e_phnum; i++, ppnt++){
+      if(ppnt->p_type == PT_DYNAMIC) {
+       tpnt->dynamic_addr = ppnt->p_vaddr + load_addr;
+       tpnt->dynamic_size = ppnt->p_filesz;
+      }
+    }
+  }
+
+  tpnt->chains = chains;
+  tpnt->loadaddr = (char *) load_addr;
+
+  brk_addr = 0;
+  rpnt = NULL;
+
+  /* At this point we are now free to examine the user application,
+     and figure out which libraries are supposed to be called.  Until
+     we have this list, we will not be completely ready for dynamic linking */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+      if(ppnt->p_type == PT_LOAD) {
+       if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) 
+         brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+      }
+      if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+       /* make sure it's really there. */
+       if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+       /* OK, we have what we need - slip this one into the list. */
+       app_tpnt = _dl_add_elf_hash_table("", 0, 
+                           app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+       _dl_loaded_modules->libtype = elf_executable;
+       _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+       _dl_loaded_modules->n_phent = dl_data[AT_PHNUM];
+       _dl_symbol_tables = rpnt = 
+          (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+       _dl_memset (rpnt, 0, sizeof (*rpnt));
+       rpnt->dyn = _dl_loaded_modules;
+       app_tpnt->usage_count++;
+       app_tpnt->symbol_scope = _dl_symbol_tables;
+       lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]);
+#ifdef ALLOW_ZERO_PLTGOT
+       if (lpnt)
+#endif
+         INIT_GOT(lpnt, _dl_loaded_modules);
+      }
+      if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+                                        this before */
+       tpnt->libname =  _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+      }
+    }
+  }
+
+  if (argv[0])
+    _dl_progname = argv[0];
+
+  /* Now we need to figure out what kind of options are selected.
+   Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */
+  {
+    _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp);
+
+    if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+        (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+         dl_data[AT_GID] == dl_data[AT_EGID]))
+    {
+      _dl_secure = 0;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+    }
+    else
+    {
+      _dl_secure = 1;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+      _dl_unsetenv("LD_LIBRARY_PATH", envp);
+      _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+      _dl_library_path = NULL;
+    }
+  }
+
+  _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
+
+  /* OK, we now have the application in the list, and we have some
+     basic stuff in place.  Now search through the list for other shared
+     libraries that should be loaded, and insert them on the list in the
+     correct order. */
+
+#ifdef USE_CACHE
+  _dl_map_cache();
+#endif
+
+  {
+    struct elf_resolve *tcurr;
+    struct elf_resolve *tpnt1;
+    char *lpnt;
+
+    if (_dl_preload) {
+      char c, *str, *str2;
+
+      str = _dl_preload;
+      while (*str == ':' || *str == ' ' || *str == '\t')
+       str++;
+      while (*str) {
+       str2 = str;
+       while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+         str2++;
+       c = *str2;
+       *str2 = '\0';
+       if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+         tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str);
+         if (!tpnt1) {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", str);
+           else {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, str);
+             _dl_exit(15);
+           }
+         } else {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count) {
+             /* this is a real hack to make ldd not print the
+                library itself when run on a library. */
+             if (_dl_strcmp(_dl_progname, str) != 0)
+               _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+                            (unsigned)tpnt1->loadaddr);
+           }
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+       *str2 = c;
+       str = str2;
+       while (*str == ':' || *str == ' ' || *str == '\t')
+         str++;
+      }
+    }
+
+    {
+      int fd;
+      struct kernel_stat st;
+      char *preload;
+
+      if (!_dl_stat(LDSO_PRELOAD, &st)) {
+       if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+         _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, 
+                      LDSO_PRELOAD);
+       } else {
+         preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, 
+                                     MAP_PRIVATE, fd, 0);
+         _dl_close (fd);
+         if (preload == (caddr_t)-1) {
+           _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, 
+                        LDSO_PRELOAD);
+         } else {
+           char c, *cp, *cp2;
+
+           /* convert all separators and comments to spaces */
+           for (cp = preload; *cp; /*nada*/) {
+             if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+               *cp++ = ' ';
+             } else if (*cp == '#') {
+               do
+                 *cp++ = ' ';
+               while (*cp != '\n' && *cp != '\0');
+             } else {
+               cp++;
+             }
+           }
+
+           /* find start of first library */
+           for (cp = preload; *cp && *cp == ' '; cp++)
+             /*nada*/;
+
+           while (*cp) {
+             /* find end of library */
+             for (cp2 = cp; *cp && *cp != ' '; cp++)
+               /*nada*/;
+             c = *cp;
+             *cp = '\0';
+
+             tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+             if (!tpnt1) {
+               if (_dl_trace_loaded_objects)
+                 _dl_fdprintf(1, "\t%s => not found\n", cp2);
+               else {
+                 _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                              _dl_progname, cp2);
+                 _dl_exit(15);
+               }
+             } else {
+               if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+                 _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+                              (unsigned)tpnt1->loadaddr);
+                rpnt->next = 
+                 (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+               _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+               rpnt = rpnt->next;
+               tpnt1->usage_count++;
+               tpnt1->symbol_scope = _dl_symbol_tables;
+               tpnt1->libtype = elf_lib;
+               rpnt->dyn = tpnt1;
+             }
+
+             /* find start of next library */
+             *cp = c;
+             for (/*nada*/; *cp && *cp == ' '; cp++)
+               /*nada*/;
+           }
+
+           _dl_munmap(preload, st.st_size+1);
+         }
+       }
+      }
+    }
+
+    for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+    {
+      for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+      {
+       if(dpnt->d_tag == DT_NEEDED)
+       {
+         lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
+           dpnt->d_un.d_val;
+         if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0)
+         {
+           struct elf_resolve * ttmp;
+           ttmp = _dl_loaded_modules;
+           while (ttmp->next) 
+             ttmp = ttmp->next;
+           ttmp->next = tpnt;
+           tpnt->prev = ttmp;
+           tpnt->next = NULL;
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           rpnt->dyn = tpnt;
+           tpnt->usage_count++;
+           tpnt->symbol_scope = _dl_symbol_tables;
+           tpnt = NULL;
+           continue;
+         }
+         if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
+         {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", lpnt);
+           else
+           {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, lpnt);
+             _dl_exit(16);
+           }
+         }
+         else
+         {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+             _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname,
+                          (unsigned)tpnt1->loadaddr);
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+      }
+    }
+  }
+
+#ifdef USE_CACHE
+  _dl_unmap_cache();
+#endif
+
+    /* ldd uses uses this.  I am not sure how you pick up the other flags */ 
+  if(_dl_trace_loaded_objects)
+    {
+      _dl_warn = _dl_getenv("LD_WARN", envp);
+      if (!_dl_warn) _dl_exit(0);
+    }
+
+  /*
+   * If the program interpreter is not in the module chain, add it.  This will
+   * be required for dlopen to be able to access the internal functions in the 
+   * dynamic linker.
+   */
+  if(tpnt) {
+    struct elf_resolve * tcurr;
+
+    tcurr = _dl_loaded_modules;
+    if (tcurr)
+      while(tcurr->next) tcurr = tcurr->next;
+    tpnt->next = NULL;
+    tpnt->usage_count++;
+
+    if (tcurr) {
+      tcurr->next = tpnt;
+      tpnt->prev = tcurr;
+    }
+    else {
+      _dl_loaded_modules = tpnt;
+      tpnt->prev = NULL;
+    }
+    if (rpnt) {
+      rpnt->next = 
+       (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+      rpnt = rpnt->next;
+    } else {
+      rpnt =   (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt, 0, sizeof (*(rpnt->next)));
+    }
+    rpnt->dyn = tpnt;
+    tpnt = NULL;
+  }
+
+  /*
+   * OK, now all of the kids are tucked into bed in their proper addresses.
+   * Now we go through and look for REL and RELA records that indicate fixups
+   * to the GOT tables.  We need to do this in reverse order so that COPY
+   * directives work correctly */
+
+
+  goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+  /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+   and we have to manually search for entries that require fixups. 
+   Solaris gets this one right, from what I understand.  */
+
+
+  if (_dl_symbol_tables)
+    goof += _dl_copy_fixups(_dl_symbol_tables);
+
+  if(goof || _dl_trace_loaded_objects) _dl_exit(0);
+
+  /* OK, at this point things are pretty much ready to run.  Now we
+     need to touch up a few items that are required, and then
+     we can let the user application have at it.  Note that
+     the dynamic linker itself is not guaranteed to be fully
+     dynamicly linked if we are using ld.so.1, so we have to look
+     up each symbol individually. */
+
+
+  _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0);
+  if (_dl_brkp) *_dl_brkp = brk_addr;
+  _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0);
+
+  if (_dl_envp) *_dl_envp = (unsigned int) envp;
+
+  {
+    int i;
+    struct elf_phdr * ppnt;
+
+  /* We had to set the protections of all pages to R/W for dynamic linking.
+     Set text pages back to R/O */
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+      if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+        tpnt->dynamic_info[DT_TEXTREL])
+       _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+                    (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                    LXFLAGS(ppnt->p_flags));
+
+  }
+
+  _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+  /*
+   * OK, fix one more thing - set up the debug_addr structure to point
+   * to our chain.  Later we may need to fill in more fields, but this
+   * should be enough for now.
+   */
+  debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
+  debug_addr->r_version = 1;
+  debug_addr->r_ldbase = load_addr;
+  debug_addr->r_brk = (unsigned long) &_dl_debug_state;
+  _dl_debug_addr = debug_addr;
+  debug_addr->r_state = RT_CONSISTENT;
+  /* This is written in this funny way to keep gcc from inlining the
+     function call. */
+  ((void (*)(void))debug_addr->r_brk)();
+
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    {
+      /* Apparently crt1 for the application is responsible for handling this.
+       * We only need to run the init/fini for shared libraries
+       */
+      if (tpnt->libtype == program_interpreter ||
+       tpnt->libtype == elf_executable) continue;
+      if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
+      tpnt->init_flag |= INIT_FUNCS_CALLED;
+      
+      if(tpnt->dynamic_info[DT_INIT]) {
+       _dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
+                                   tpnt->dynamic_info[DT_INIT]);
+       (*_dl_elf_init)();
+      }
+      if(_dl_atexit && tpnt->dynamic_info[DT_FINI])
+      {
+        (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+      }
+#undef DL_DEBUG
+#ifdef DL_DEBUG
+      else
+      {
+       _dl_fdprintf(2, tpnt->libname);
+       _dl_fdprintf(2, ": ");
+       if (!_dl_atexit)
+         _dl_fdprintf(2, "The address is atexit () is 0x0.");
+       if (!tpnt->dynamic_info[DT_FINI])
+         _dl_fdprintf(2, "Invalid .fini section.");
+       _dl_fdprintf(2, "\n");
+      }
+#endif
+#undef DL_DEBUG
+   }
+
+  /* OK we are done here.  Turn out the lights, and lock up. */
+  _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY];
+
+
+  /*
+   * Transfer control to the application.
+   */
+  START();
+}
+
+int _dl_fixup(struct elf_resolve * tpnt)
+{
+  int goof = 0;
+  if(tpnt->next) goof += _dl_fixup(tpnt->next);
+
+  if(tpnt->dynamic_info[DT_REL]) {
+#ifdef ELF_USES_RELOCA
+    _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+    _dl_exit(17);
+#else
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+                                            tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+                                            tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+    _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+    _dl_exit(18);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_JMPREL])
+    {
+      if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
+      tpnt->init_flag |= JMP_RELOCS_DONE;
+      
+      if(! _dl_not_lazy || *_dl_not_lazy == 0)
+       _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+                                             tpnt->dynamic_info[DT_PLTRELSZ], 0);
+      else
+       goof +=  _dl_parse_relocation_information(tpnt,
+                                                 tpnt->dynamic_info[DT_JMPREL],
+                                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
+    }
+  return goof;
+}
+
+void * _dl_malloc(int size) {
+  void * retval;
+
+  if(_dl_malloc_function)
+       return (*_dl_malloc_function)(size);
+
+  if(_dl_malloc_addr-_dl_mmap_zero+size>4096) {
+       _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size,
+                               PROT_READ | PROT_WRITE, 
+                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if(_dl_mmap_check_error(_dl_mmap_zero)) {
+           _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+           _dl_exit(20);
+       }
+  }
+  retval = _dl_malloc_addr;
+  _dl_malloc_addr += size;
+
+  /*
+   * Align memory to 4 byte boundary.  Some platforms require this, others
+   * simply get better performance.
+   */
+  _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3));
+  return retval;
+}
+
+char * _dl_getenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  while ((pnt = *envp++)) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if (!*pnt || *pnt != '=' || *pnt1)
+      continue;
+    return pnt+1;
+  }
+  return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  char **newenvp = envp;
+  for (pnt = *envp; pnt; pnt = *++envp) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if(!*pnt || *pnt != '=' || *pnt1)
+      *newenvp++ = *envp;
+  }
+  *newenvp++ = *envp;
+  return;
+}
+
+char * _dl_strdup(const char * string){
+  char * retval;
+  int len;
+
+  len = _dl_strlen(string);
+  retval = _dl_malloc(len + 1);
+  _dl_strcpy(retval, string);
+  return retval;
+}
+
+/* In principle we could do the .fini stuff here, but we already
+   registered this stuff with atexit */
+int _dl_interpreter_exit(int exitcode){
+/*  _dl_fdprintf(2, "Hey, look where I am!\n"); */
+  return 0;
+}
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
new file mode 100644 (file)
index 0000000..9d1cd0f
--- /dev/null
@@ -0,0 +1,588 @@
+/* Load an ELF sharable library into memory.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* This file contains the helper routines to load an ELF sharable
+   library into memory and add the symbol table info to the chain. */
+
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "string.h"
+/*#include <stdlib.h>*/
+#include <linux/mman.h>
+#include <linux/stat.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+#ifdef USE_CACHE
+#include "../config.h"
+#endif
+
+extern char *_dl_progname;
+
+#ifdef USE_CACHE
+
+static caddr_t _dl_cache_addr = NULL;
+static size_t _dl_cache_size = 0;
+
+int _dl_map_cache(void)
+{
+  int fd;
+  struct kernel_stat st;
+  header_t *header;
+  libentry_t *libent;
+  int i, strtabsize;
+
+  if (_dl_cache_addr == (caddr_t)-1)
+    return -1;
+  else if (_dl_cache_addr != NULL)
+    return 0;
+
+  if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
+  {
+    _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
+    _dl_cache_addr = (caddr_t)-1; /* so we won't try again */
+    return -1;
+  }
+
+  _dl_cache_size = st.st_size;
+  _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
+                                    MAP_SHARED, fd, 0);
+  _dl_close (fd);
+  if (_dl_cache_addr == (caddr_t)-1)
+  {
+    _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
+    return -1;
+  }
+
+  header = (header_t *)_dl_cache_addr;
+
+  if (_dl_cache_size < sizeof (header_t) ||
+      _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
+      _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
+      _dl_cache_size < 
+        (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
+      _dl_cache_addr[_dl_cache_size-1] != '\0')
+  {
+    _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+    goto fail;
+  }
+
+  strtabsize = _dl_cache_size - sizeof (header_t) - 
+    header->nlibs * sizeof (libentry_t);
+  libent = (libentry_t *)&header[1];
+
+  for (i = 0; i < header->nlibs; i++)
+  {
+    if (libent[i].sooffset >= strtabsize ||
+       libent[i].liboffset >= strtabsize)
+    {
+      _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+      goto fail;
+    }
+  }
+
+  return 0;
+
+fail:
+  _dl_munmap(_dl_cache_addr, _dl_cache_size);
+  _dl_cache_addr = (caddr_t)-1;
+  return -1;
+}
+
+int _dl_unmap_cache(void)
+{
+  if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
+    return -1;
+
+#if 1
+  _dl_munmap (_dl_cache_addr, _dl_cache_size);
+  _dl_cache_addr = NULL;
+#endif
+
+  return 0;
+}
+
+#endif
+
+/*
+ * Used to return error codes back to dlopen et. al.
+ */
+
+unsigned int _dl_error_number;
+unsigned int _dl_internal_error_number;
+
+struct elf_resolve * _dl_load_shared_library(int secure, 
+       struct elf_resolve * tpnt, char * full_libname) {
+  char * pnt, *pnt1, *pnt2;
+  struct elf_resolve *tpnt1 = NULL;
+  char mylibname[2050];
+  char * libname;
+
+  _dl_internal_error_number = 0;
+
+  /* quick hack to ensure mylibname buffer doesn't overflow.  don't 
+     allow full_libname or any directory to be longer than 1024. */
+  if (_dl_strlen(full_libname) > 1024)
+    goto goof;
+
+  pnt = libname = full_libname;
+  while (*pnt) {
+    if(*pnt == '/') libname = pnt+1;
+    pnt++;
+  }
+
+ /* If the filename has any '/', try it straight and leave it at that.
+     For IBCS2 compatibility under linux, we substitute the string 
+     /usr/i486-sysv4/lib for /usr/lib in library names. */
+
+  if (libname != full_libname) {
+    tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
+    if (tpnt1)
+      return tpnt1;
+    goto goof;
+  }
+
+  /*
+   * The ABI specifies that RPATH is searched before LD_*_PATH or
+   * the default path of /usr/lib.
+   * Check in rpath directories 
+   */
+  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+    if (tpnt->libtype == elf_executable) {
+      pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
+      if(pnt1) {
+       pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
+       while(*pnt1){
+         pnt2 = mylibname;
+         while(*pnt1 && *pnt1 != ':') {
+           if (pnt2 - mylibname < 1024)
+             *pnt2++ = *pnt1++;
+           else
+             pnt1++;
+         }
+         if (pnt2 - mylibname >= 1024)
+           break;
+         if(pnt2[-1] != '/') *pnt2++ = '/';
+         pnt = libname;
+         while(*pnt) *pnt2++  = *pnt++;
+         *pnt2++ = 0;
+         tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+         if(tpnt1) return tpnt1;
+         if(*pnt1 == ':') pnt1++;
+       }
+      }
+    }
+  }
+  
+
+  /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
+  pnt1 = _dl_library_path;
+  if (pnt1 && *pnt1) {
+    while (*pnt1) {
+      pnt2 = mylibname;
+      while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
+       if (pnt2 - mylibname < 1024)
+         *pnt2++ = *pnt1++;
+       else
+         pnt1++;
+      }
+      if (pnt2 - mylibname >= 1024)
+       break;
+      if(pnt2[-1] != '/') *pnt2++ = '/';
+      pnt = libname;
+      while(*pnt) *pnt2++  = *pnt++;
+      *pnt2++ = 0;
+      tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+      if(tpnt1) return tpnt1;
+      if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
+    }
+  }
+
+
+  /*
+   * Where should the cache be searched?  There is no such concept in the
+   * ABI, so we have some flexibility here.  For now, search it before
+   * the default path of /usr/lib.
+   */
+#ifdef USE_CACHE
+  if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
+  {
+    int i;
+    header_t *header = (header_t *)_dl_cache_addr;
+    libentry_t *libent = (libentry_t *)&header[1];
+    char *strs = (char *)&libent[header->nlibs];
+
+    for (i = 0; i < header->nlibs; i++)
+    {
+      if ((libent[i].flags == LIB_ELF || 
+          libent[i].flags == LIB_ELF_LIBC5) &&
+         _dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
+         (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
+       return tpnt1;
+    }
+  }
+#endif
+
+
+#ifdef UCLIBC_DEVEL
+
+  /* Check in /usr/<arch>-linux-uclibc/lib */
+  pnt1 = UCLIBC_INSTALL_DIR"/lib";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+  
+#else /* UCLIBC_DEVEL */
+
+  /* Check in /usr/lib */
+  pnt1 = "/usr/lib/";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+  
+  /* Check in /lib */
+  /* try "/lib/". */
+  pnt1 = "/lib/";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+#endif /* UCLIBC_DEVEL */
+
+goof:
+  /* Well, we shot our wad on that one.  All we can do now is punt */
+  if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
+       else _dl_error_number = DL_ERROR_NOFILE;
+  return NULL;
+}
+
+/*
+ * Read one ELF library into memory, mmap it into the correct locations and
+ * add the symbol info to the symbol chain.  Perform any relocations that
+ * are required.
+ */
+
+//extern _elf_rtbndr(void);
+
+struct elf_resolve * _dl_load_elf_shared_library(int secure, 
+        char * libname, int flag) {
+  struct elfhdr * epnt;
+  unsigned int dynamic_addr = 0;
+  unsigned int dynamic_size = 0;
+  struct dynamic * dpnt;
+  struct elf_resolve * tpnt;
+  struct elf_phdr * ppnt;
+  int piclib;
+  char * status;
+  int flags;
+  char header[4096];
+  int dynamic_info[24];
+  int * lpnt;
+  unsigned int libaddr;
+  unsigned int minvma=0xffffffff, maxvma=0;
+  
+  int i;
+  int infile;
+
+  /* If this file is already loaded, skip this step */
+  tpnt = _dl_check_hashed_files(libname);
+  if(tpnt) return tpnt;
+
+  /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
+     we don't load the library if it isn't setuid. */
+
+  if (secure) {
+    struct kernel_stat st;
+    if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
+      return NULL;
+  }
+
+  libaddr = 0;
+  infile = _dl_open(libname, O_RDONLY);
+  if(infile < 0)
+  {
+#if 0
+    /*
+     * NO!  When we open shared libraries we may search several paths.
+     * it is inappropriate to generate an error here.
+     */
+    _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
+#endif
+    _dl_internal_error_number = DL_ERROR_NOFILE;
+    return NULL;
+  }
+  _dl_read(infile, header, sizeof(header));
+  epnt = (struct elfhdr *) header;
+  if (epnt->e_ident[0] != 0x7f ||
+      epnt->e_ident[1] != 'E' ||
+      epnt->e_ident[2] != 'L' ||
+      epnt->e_ident[3] != 'F') {
+    _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
+    _dl_internal_error_number = DL_ERROR_NOTELF;
+    _dl_close(infile);
+    return NULL;
+  };
+  
+  if((epnt->e_type != ET_DYN) || 
+     (epnt->e_machine != MAGIC1 
+#ifdef MAGIC2
+      && epnt->e_machine != MAGIC2
+#endif
+      )){
+    _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
+    _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
+                _dl_progname, libname);
+    _dl_close(infile);
+    return NULL;
+  };
+
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+  piclib = 1;
+  for(i=0;i < epnt->e_phnum; i++){
+
+    if(ppnt->p_type == PT_DYNAMIC) {
+      if (dynamic_addr)
+       _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
+                    _dl_progname, libname);
+      dynamic_addr = ppnt->p_vaddr;
+      dynamic_size = ppnt->p_filesz;
+    };
+
+    if(ppnt->p_type == PT_LOAD) {
+       /* See if this is a PIC library. */
+       if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+           piclib = 0;
+           minvma=ppnt->p_vaddr;
+       }
+       if(piclib && ppnt->p_vaddr < minvma) {
+           minvma = ppnt->p_vaddr;
+       }
+       if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
+           maxvma = ppnt->p_vaddr + ppnt->p_memsz;
+       }
+     }
+    ppnt++;
+  };
+
+  maxvma=(maxvma+0xfffU)&~0xfffU;
+  minvma=minvma&~0xffffU;
+  
+  flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
+  if(!piclib) flags |= MAP_FIXED;
+  
+  status = (char *) _dl_mmap((char *) (piclib?0:minvma),
+                         maxvma-minvma, 
+                         PROT_NONE, 
+                         flags | MAP_ANONYMOUS, -1,
+                         0);
+  if(_dl_mmap_check_error(status)) {
+    _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+    _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+    _dl_close(infile);
+     return NULL;
+  };
+  libaddr=(unsigned int)status;
+  flags|=MAP_FIXED;
+
+  /* Get the memory to store the library */
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+  
+  for(i=0;i < epnt->e_phnum; i++){
+    if(ppnt->p_type == PT_LOAD) {
+
+      /* See if this is a PIC library. */
+      if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+       piclib = 0;
+       /* flags |= MAP_FIXED; */
+      }
+
+
+      
+      if(ppnt->p_flags & PF_W) {
+       unsigned int map_size;
+       char * cpnt;
+       
+       status = (char *) _dl_mmap((char *) ((piclib?libaddr:0)  +
+                                            (ppnt->p_vaddr & 0xfffff000)),
+                         (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, 
+                         LXFLAGS(ppnt->p_flags), 
+                         flags, infile,
+                         ppnt->p_offset & 0x7ffff000);
+       
+       if(_dl_mmap_check_error(status)) {
+           _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+           _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+           _dl_munmap((char *)libaddr, maxvma-minvma);
+           _dl_close(infile);
+           return NULL;
+       };
+       
+       /* Pad the last page with zeroes. */
+       cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
+       while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
+
+/* I am not quite sure if this is completely correct to do or not, but
+   the basic way that we handle bss segments is that we mmap /dev/zero if
+   there are any pages left over that are not mapped as part of the file */
+
+       map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
+       if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
+         status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0), 
+                           ppnt->p_vaddr + ppnt->p_memsz - map_size,
+                           LXFLAGS(ppnt->p_flags),
+                           flags | MAP_ANONYMOUS, -1, 0);
+      } else
+       status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + 
+                                  (piclib?libaddr:0), 
+                         (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, 
+                         LXFLAGS(ppnt->p_flags), 
+                         flags, infile, 
+                         ppnt->p_offset & 0x7ffff000);
+      if(_dl_mmap_check_error(status)) {
+       _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+       _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+       _dl_munmap((char *)libaddr, maxvma-minvma);
+       _dl_close(infile);
+       return NULL;
+      };
+
+      /* if(libaddr == 0 && piclib) {
+       libaddr = (unsigned int) status;
+       flags |= MAP_FIXED;
+      }; */
+    };
+    ppnt++;
+  };
+  _dl_close(infile);
+  
+  /* For a non-PIC library, the addresses are all absolute */
+  if(piclib) {
+    dynamic_addr += (unsigned int) libaddr;
+  }
+
+ /* 
+  * OK, the ELF library is now loaded into VM in the correct locations
+  * The next step is to go through and do the dynamic linking (if needed).
+  */
+  
+  /* Start by scanning the dynamic section to get all of the pointers */
+  
+  if(!dynamic_addr) {
+    _dl_internal_error_number = DL_ERROR_NODYNAMIC;
+    _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
+    return NULL;
+  }
+
+  dpnt = (struct dynamic *) dynamic_addr;
+
+  dynamic_size = dynamic_size / sizeof(struct dynamic);
+  _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
+  for(i=0; i< dynamic_size; i++){
+    if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
+    dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+    if(dpnt->d_tag == DT_TEXTREL ||
+       SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
+    dpnt++;
+  };
+
+  /* If the TEXTREL is set, this means that we need to make the pages
+     writable before we perform relocations.  Do this now. They get set back
+     again later. */
+
+  if (dynamic_info[DT_TEXTREL]) {
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+  for(i=0;i < epnt->e_phnum; i++, ppnt++){
+    if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+      _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
+                  (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                  PROT_READ | PROT_WRITE | PROT_EXEC);
+  }
+  }
+
+
+  tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr, 
+                             dynamic_size);
+
+  tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
+  tpnt->n_phent = epnt->e_phnum;
+
+  /*
+   * OK, the next thing we need to do is to insert the dynamic linker into
+   * the proper entry in the GOT so that the PLT symbols can be properly
+   * resolved. 
+   */
+  
+  lpnt = (int *) dynamic_info[DT_PLTGOT];
+  
+  if(lpnt) {
+    lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
+    INIT_GOT(lpnt, tpnt);
+  };
+  
+  return tpnt;
+}
+
+/* Ugly, ugly.  Some versions of the SVr4 linker fail to generate COPY
+   relocations for global variables that are present both in the image and
+   the shared library.  Go through and do it manually.  If the images
+   are guaranteed to be generated by a trustworthy linker, then this
+   step can be skipped. */
+
+int _dl_copy_fixups(struct dyn_elf * rpnt)
+{
+  int goof = 0;
+  struct elf_resolve * tpnt;
+
+  if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
+  else return 0;
+
+  tpnt = rpnt->dyn;
+       
+  if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
+  tpnt->init_flag |= COPY_RELOCS_DONE;
+  
+#ifdef ELF_USES_RELOCA
+  goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
+                                          tpnt->dynamic_info[DT_RELASZ], 0);
+
+#else
+  goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
+                                          tpnt->dynamic_info[DT_RELSZ], 0);
+
+#endif
+  return goof;
+}
+
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
new file mode 100644 (file)
index 0000000..4eab974
--- /dev/null
@@ -0,0 +1,284 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* Various symbol table handling functions, including symbol lookup */
+
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/elf.h>
+
+#include "libdl/dlfcn.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+#include "sysdep.h"
+
+/*
+ * This is the start of the linked list that describes all of the files present
+ * in the system with pointers to all of the symbol, string, and hash tables, 
+ * as well as all of the other good stuff in the binary.
+ */
+
+struct elf_resolve * _dl_loaded_modules = NULL;
+
+/*
+ * This is the list of modules that are loaded when the image is first
+ * started.  As we add more via dlopen, they get added into other
+ * chains.
+ */
+struct dyn_elf * _dl_symbol_tables = NULL;
+
+/*
+ * This is the list of modules that are loaded via dlopen.  We may need
+ * to search these for RTLD_GLOBAL files.
+ */
+struct dyn_elf * _dl_handles = NULL;
+
+
+/*
+ * This is the hash function that is used by the ELF linker to generate
+ * the hash table that each executable and library is required to
+ * have.  We need it to decode the hash table.
+ */
+
+unsigned long _dl_elf_hash(const char * name){
+  unsigned long hash = 0;
+  unsigned long tmp;
+
+  while (*name){
+    hash = (hash << 4) + *name++;
+    if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
+    hash &= ~tmp;
+  };
+  return hash;
+}
+
+/*
+ * Check to see if a library has already been added to the hash chain.
+ */
+struct elf_resolve * _dl_check_hashed_files(char * libname){
+  struct elf_resolve * tpnt;
+  int len = _dl_strlen(libname);
+
+  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+    if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
+       (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
+      return tpnt;
+  }
+
+  return NULL;
+}
+
+/*
+ * We call this function when we have just read an ELF library or executable.
+ * We add the relevant info to the symbol chain, so that we can resolve all
+ * externals properly.
+ */
+
+struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+                                       char * loadaddr,
+                                       unsigned int * dynamic_info,
+                                       unsigned int dynamic_addr,
+                                       unsigned int dynamic_size){
+  unsigned int *  hash_addr;
+  struct elf_resolve * tpnt;
+  int i;
+
+  if (!_dl_loaded_modules) {
+    tpnt = _dl_loaded_modules = 
+      (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+    _dl_memset (tpnt, 0, sizeof (*tpnt));
+  }
+  else {
+    tpnt = _dl_loaded_modules;
+    while(tpnt->next) tpnt = tpnt->next;
+    tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+    _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
+    tpnt->next->prev = tpnt;
+    tpnt = tpnt->next;
+  };
+  
+  tpnt->next = NULL;
+  tpnt->init_flag = 0;
+  tpnt->libname = _dl_strdup(libname);
+  tpnt->dynamic_addr = dynamic_addr;
+  tpnt->dynamic_size = dynamic_size;
+  tpnt->libtype = loaded_file;
+
+  if( dynamic_info[DT_HASH] != 0 )
+  {
+    hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
+    tpnt->nbucket = *hash_addr++;
+    tpnt->nchain = *hash_addr++;
+    tpnt->elf_buckets = hash_addr;
+    hash_addr += tpnt->nbucket;
+    tpnt->chains = hash_addr;
+  }
+  tpnt->loadaddr = loadaddr;
+  for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
+  return tpnt;
+}
+
+
+/*
+ * This function resolves externals, and this is either called when we process
+ * relocations or when we call an entry in the PLT table for the first time.
+ */
+
+char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, 
+                    unsigned int instr_addr, struct elf_resolve * f_tpnt, 
+                    int copyrel){
+  struct elf_resolve * tpnt;
+  int si;
+  char * pnt;
+  int    pass;
+  char * strtab;
+  struct elf32_sym * symtab;
+  unsigned int elf_hash_number, hn;
+  char * weak_result;
+  struct elf_resolve * first_def;
+  struct dyn_elf * rpnt, first;
+  char * data_result = 0;         /* nakao */
+
+  weak_result = 0;
+  elf_hash_number = _dl_elf_hash(name);
+
+  /* A quick little hack to make sure that any symbol in the executable
+  will be preferred to one in a shared library.  This is necessary so
+  that any shared library data symbols referenced in the executable
+  will be seen at the same address by the executable, shared libraries
+  and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
+  if(!copyrel && rpnt1) {
+      first=(*_dl_symbol_tables);
+      first.next=rpnt1;
+      rpnt1=(&first);
+  }
+  
+  /*
+   * The passes are so that we can first search the regular symbols
+   * for whatever module was specified, and then search anything
+   * loaded with RTLD_GLOBAL.  When pass is 1, it means we are just
+   * starting the first dlopened module, and anything above that
+   * is just the next one in the chain.
+   */
+  for(pass = 0; (1==1); pass++)
+    {
+      
+      /*
+       * If we are just starting to search for RTLD_GLOBAL, setup
+       * the pointer for the start of the search.
+       */
+      if( pass == 1) {
+       rpnt1 = _dl_handles;
+      }
+
+      /*
+       * Anything after this, we need to skip to the next module.
+       */
+      else if( pass >= 2) {
+       rpnt1 = rpnt1->next_handle;
+      }
+
+      /*
+       * Make sure we still have a module, and make sure that this
+       * module was loaded with RTLD_GLOBAL.
+       */
+      if( pass != 0 )
+       {
+         if( rpnt1 == NULL ) break;
+         if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
+       }
+
+      for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); 
+         rpnt; rpnt = rpnt->next) {
+       tpnt = rpnt->dyn;
+       
+       /*
+        * The idea here is that if we are using dlsym, we want to
+        * first search the entire chain loaded from dlopen, and
+        * return a result from that if we found anything.  If this
+        * fails, then we continue the search into the stuff loaded
+        * when the image was activated.  For normal lookups, we start
+        * with rpnt == NULL, so we should never hit this.  
+        */
+       if( tpnt->libtype == elf_executable
+          && weak_result != 0 )
+         {
+           break;
+         }
+       
+       /*
+        * Avoid calling .urem here.
+        */
+       do_rem(hn, elf_hash_number, tpnt->nbucket);
+       symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + 
+                                      tpnt->loadaddr);
+       strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+       /*
+        * This crap is required because the first instance of a
+        * symbol on the chain will be used for all symbol references.
+        * Thus this instance must be resolved to an address that
+        * contains the actual function, 
+        */
+       
+       first_def = NULL;
+       
+       for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
+         pnt = strtab + symtab[si].st_name;
+         
+         if(_dl_strcmp(pnt, name) == 0 && 
+            (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
+             ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
+             ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
+            symtab[si].st_value != 0) {
+           
+           /* Here we make sure that we find a module where the symbol is
+            * actually defined.
+            */
+           
+           if(f_tpnt) {
+             if(!first_def) first_def = tpnt;
+             if(first_def == f_tpnt && symtab[si].st_shndx == 0)
+               continue;
+           }
+           
+           switch(ELF32_ST_BIND(symtab[si].st_info)){
+           case STB_GLOBAL:
+             if ( tpnt->libtype != elf_executable
+               && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
+               data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
+               break;                                              /* nakao */
+             } else                                                /* nakao */
+               return tpnt->loadaddr + symtab[si].st_value;
+           case STB_WEAK:
+             if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
+             break;
+           default:  /* Do local symbols need to be examined? */
+             break;
+           }
+         }
+       }
+      }
+    }
+  if (data_result) return data_result; /* nakao */
+  return weak_result;
+}
diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c
new file mode 100644 (file)
index 0000000..4eab974
--- /dev/null
@@ -0,0 +1,284 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* Various symbol table handling functions, including symbol lookup */
+
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/elf.h>
+
+#include "libdl/dlfcn.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+#include "sysdep.h"
+
+/*
+ * This is the start of the linked list that describes all of the files present
+ * in the system with pointers to all of the symbol, string, and hash tables, 
+ * as well as all of the other good stuff in the binary.
+ */
+
+struct elf_resolve * _dl_loaded_modules = NULL;
+
+/*
+ * This is the list of modules that are loaded when the image is first
+ * started.  As we add more via dlopen, they get added into other
+ * chains.
+ */
+struct dyn_elf * _dl_symbol_tables = NULL;
+
+/*
+ * This is the list of modules that are loaded via dlopen.  We may need
+ * to search these for RTLD_GLOBAL files.
+ */
+struct dyn_elf * _dl_handles = NULL;
+
+
+/*
+ * This is the hash function that is used by the ELF linker to generate
+ * the hash table that each executable and library is required to
+ * have.  We need it to decode the hash table.
+ */
+
+unsigned long _dl_elf_hash(const char * name){
+  unsigned long hash = 0;
+  unsigned long tmp;
+
+  while (*name){
+    hash = (hash << 4) + *name++;
+    if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
+    hash &= ~tmp;
+  };
+  return hash;
+}
+
+/*
+ * Check to see if a library has already been added to the hash chain.
+ */
+struct elf_resolve * _dl_check_hashed_files(char * libname){
+  struct elf_resolve * tpnt;
+  int len = _dl_strlen(libname);
+
+  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+    if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
+       (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
+      return tpnt;
+  }
+
+  return NULL;
+}
+
+/*
+ * We call this function when we have just read an ELF library or executable.
+ * We add the relevant info to the symbol chain, so that we can resolve all
+ * externals properly.
+ */
+
+struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+                                       char * loadaddr,
+                                       unsigned int * dynamic_info,
+                                       unsigned int dynamic_addr,
+                                       unsigned int dynamic_size){
+  unsigned int *  hash_addr;
+  struct elf_resolve * tpnt;
+  int i;
+
+  if (!_dl_loaded_modules) {
+    tpnt = _dl_loaded_modules = 
+      (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+    _dl_memset (tpnt, 0, sizeof (*tpnt));
+  }
+  else {
+    tpnt = _dl_loaded_modules;
+    while(tpnt->next) tpnt = tpnt->next;
+    tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+    _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
+    tpnt->next->prev = tpnt;
+    tpnt = tpnt->next;
+  };
+  
+  tpnt->next = NULL;
+  tpnt->init_flag = 0;
+  tpnt->libname = _dl_strdup(libname);
+  tpnt->dynamic_addr = dynamic_addr;
+  tpnt->dynamic_size = dynamic_size;
+  tpnt->libtype = loaded_file;
+
+  if( dynamic_info[DT_HASH] != 0 )
+  {
+    hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
+    tpnt->nbucket = *hash_addr++;
+    tpnt->nchain = *hash_addr++;
+    tpnt->elf_buckets = hash_addr;
+    hash_addr += tpnt->nbucket;
+    tpnt->chains = hash_addr;
+  }
+  tpnt->loadaddr = loadaddr;
+  for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
+  return tpnt;
+}
+
+
+/*
+ * This function resolves externals, and this is either called when we process
+ * relocations or when we call an entry in the PLT table for the first time.
+ */
+
+char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, 
+                    unsigned int instr_addr, struct elf_resolve * f_tpnt, 
+                    int copyrel){
+  struct elf_resolve * tpnt;
+  int si;
+  char * pnt;
+  int    pass;
+  char * strtab;
+  struct elf32_sym * symtab;
+  unsigned int elf_hash_number, hn;
+  char * weak_result;
+  struct elf_resolve * first_def;
+  struct dyn_elf * rpnt, first;
+  char * data_result = 0;         /* nakao */
+
+  weak_result = 0;
+  elf_hash_number = _dl_elf_hash(name);
+
+  /* A quick little hack to make sure that any symbol in the executable
+  will be preferred to one in a shared library.  This is necessary so
+  that any shared library data symbols referenced in the executable
+  will be seen at the same address by the executable, shared libraries
+  and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
+  if(!copyrel && rpnt1) {
+      first=(*_dl_symbol_tables);
+      first.next=rpnt1;
+      rpnt1=(&first);
+  }
+  
+  /*
+   * The passes are so that we can first search the regular symbols
+   * for whatever module was specified, and then search anything
+   * loaded with RTLD_GLOBAL.  When pass is 1, it means we are just
+   * starting the first dlopened module, and anything above that
+   * is just the next one in the chain.
+   */
+  for(pass = 0; (1==1); pass++)
+    {
+      
+      /*
+       * If we are just starting to search for RTLD_GLOBAL, setup
+       * the pointer for the start of the search.
+       */
+      if( pass == 1) {
+       rpnt1 = _dl_handles;
+      }
+
+      /*
+       * Anything after this, we need to skip to the next module.
+       */
+      else if( pass >= 2) {
+       rpnt1 = rpnt1->next_handle;
+      }
+
+      /*
+       * Make sure we still have a module, and make sure that this
+       * module was loaded with RTLD_GLOBAL.
+       */
+      if( pass != 0 )
+       {
+         if( rpnt1 == NULL ) break;
+         if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
+       }
+
+      for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); 
+         rpnt; rpnt = rpnt->next) {
+       tpnt = rpnt->dyn;
+       
+       /*
+        * The idea here is that if we are using dlsym, we want to
+        * first search the entire chain loaded from dlopen, and
+        * return a result from that if we found anything.  If this
+        * fails, then we continue the search into the stuff loaded
+        * when the image was activated.  For normal lookups, we start
+        * with rpnt == NULL, so we should never hit this.  
+        */
+       if( tpnt->libtype == elf_executable
+          && weak_result != 0 )
+         {
+           break;
+         }
+       
+       /*
+        * Avoid calling .urem here.
+        */
+       do_rem(hn, elf_hash_number, tpnt->nbucket);
+       symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + 
+                                      tpnt->loadaddr);
+       strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+       /*
+        * This crap is required because the first instance of a
+        * symbol on the chain will be used for all symbol references.
+        * Thus this instance must be resolved to an address that
+        * contains the actual function, 
+        */
+       
+       first_def = NULL;
+       
+       for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
+         pnt = strtab + symtab[si].st_name;
+         
+         if(_dl_strcmp(pnt, name) == 0 && 
+            (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
+             ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
+             ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
+            symtab[si].st_value != 0) {
+           
+           /* Here we make sure that we find a module where the symbol is
+            * actually defined.
+            */
+           
+           if(f_tpnt) {
+             if(!first_def) first_def = tpnt;
+             if(first_def == f_tpnt && symtab[si].st_shndx == 0)
+               continue;
+           }
+           
+           switch(ELF32_ST_BIND(symtab[si].st_info)){
+           case STB_GLOBAL:
+             if ( tpnt->libtype != elf_executable
+               && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
+               data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
+               break;                                              /* nakao */
+             } else                                                /* nakao */
+               return tpnt->loadaddr + symtab[si].st_value;
+           case STB_WEAK:
+             if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
+             break;
+           default:  /* Do local symbols need to be examined? */
+             break;
+           }
+         }
+       }
+      }
+    }
+  if (data_result) return data_result; /* nakao */
+  return weak_result;
+}
diff --git a/ldso/ldso/hash.h b/ldso/ldso/hash.h
new file mode 100644 (file)
index 0000000..2eeda2d
--- /dev/null
@@ -0,0 +1,113 @@
+#include "link.h"
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT      ((void*)-1)
+#endif
+
+struct dyn_elf{
+  unsigned int flags;
+  struct elf_resolve * dyn;
+  struct dyn_elf * next_handle;  /* Used by dlopen et al. */
+  struct dyn_elf * next;
+};
+struct elf_resolve{
+  /* These entries must be in this order to be compatible with the interface used
+     by gdb to obtain the list of symbols. */
+  char * loadaddr;
+  char * libname;
+  unsigned int dynamic_addr;
+  struct elf_resolve * next;
+  struct elf_resolve * prev;
+  /* Nothing after this address is used by gdb. */
+  enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+  struct dyn_elf * symbol_scope;
+  unsigned short usage_count;
+  unsigned short int init_flag;
+  unsigned int nbucket;
+  unsigned int * elf_buckets;
+  /*
+   * These are only used with ELF style shared libraries
+   */
+  unsigned int nchain;
+  unsigned int * chains;
+  unsigned int dynamic_info[24];
+
+  unsigned int dynamic_size;
+  unsigned int n_phent;
+  struct elf_phdr * ppnt;
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+  int r_version;
+  struct elf_resolve * link_map;
+  unsigned long brk_fun;
+  enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+  unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf     * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf    * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, 
+                                              char * loadaddr, 
+                                              unsigned int * dynamic_info, 
+                                              unsigned int dynamic_addr, 
+                                              unsigned int dynamic_size);
+extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, 
+                           unsigned int instr_addr, 
+                           struct elf_resolve * f_tpnt, 
+                           int copyrel);
+
+extern int _dl_linux_dynamic_link(void);
+
+#ifdef __mc68000__
+/* On m68k constant strings are referenced through the GOT. */
+/* XXX Requires load_addr to be defined. */
+#define SEND_STDERR(X)                         \
+  { const char *__s = (X);                     \
+    if (__s < (const char *) load_addr) __s += load_addr;      \
+    _dl_write (2, __s, _dl_strlen (__s));      \
+  }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
+#endif
+extern int _dl_fdprintf(int, const char *, ...);
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern char * _dl_strdup(const char *);
+extern inline int _dl_symbol(char * name);
+unsigned long _dl_elf_hash(const char * name);
+
+extern inline int _dl_symbol(char * name)
+{
+  if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+    return 0;
+  return 1;
+}
+
+#define DL_ERROR_NOFILE 1
+#define DL_ERROR_NOZERO 2
+#define DL_ERROR_NOTELF 3
+#define DL_ERROR_NOTMAGIC 4
+#define DL_ERROR_NOTDYN 5
+#define DL_ERROR_MMAP_FAILED 6
+#define DL_ERROR_NODYNAMIC 7
+#define DL_WRONG_RELOCS 8
+#define DL_BAD_HANDLE 9
+#define DL_NO_SYMBOL 10
+
diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h
new file mode 100644 (file)
index 0000000..9bbeef1
--- /dev/null
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve; \
+  GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)){           \
+       case R_386_32:          \
+         *REL += SYMBOL;               \
+         break;                \
+       case R_386_PC32:                \
+         *REL += SYMBOL - (unsigned int) REL;          \
+         break;                \
+       case R_386_GLOB_DAT:            \
+       case R_386_JMP_SLOT:            \
+         *REL = SYMBOL;                \
+         break;                \
+       case R_386_RELATIVE:            \
+         *REL += (unsigned int) LOAD;          \
+         break;                \
+       default:                \
+         _dl_exit(1);          \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START()                \
+       __asm__ volatile ("leave\n\t" \
+                   "jmp *%%eax\n\t"    \
+                   : "=a" (status) :   \
+                   "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base)  result = (n % base)
diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c
new file mode 100644 (file)
index 0000000..3347882
--- /dev/null
@@ -0,0 +1,321 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char * _dl_reltypes[] = {"R_386_NONE","R_386_32","R_386_PC32","R_386_GOT32",
+                      "R_386_PLT32","R_386_COPY","R_386_GLOB_DAT",
+                      "R_386_JMP_SLOT","R_386_RELATIVE","R_386_GOTOFF",
+                      "R_386_GOTPC","R_386_NUM"};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+References to symbols in sharable libraries can be resolved by either
+an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "../string.h"
+#include "../syscall.h"
+
+#define SVR4_COMPATIBILITY
+
+extern char *_dl_progname;
+
+extern int _dl_linux_resolve(void);
+
+unsigned int _dl_linux_resolver(int dummy, int i)
+{
+  unsigned int * sp;
+  int reloc_entry;
+  int reloc_type;
+  struct elf32_rel * this_reloc;
+  char * strtab;
+  struct elf32_sym * symtab; 
+  struct elf32_rel * rel_addr;
+  struct elf_resolve * tpnt;
+  int symtab_index;
+  char * new_addr;
+  char ** got_addr;
+  unsigned int instr_addr;
+  sp = &i;  
+  reloc_entry = sp[1];
+  tpnt = (struct elf_resolve *) sp[0];
+
+  rel_addr = (struct elf32_rel *) (tpnt->dynamic_info[DT_JMPREL] + 
+                                  tpnt->loadaddr);
+
+  this_reloc = rel_addr + (reloc_entry >> 3);
+  reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+  symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+
+  if (reloc_type != R_386_JMP_SLOT) {
+    _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n",
+                _dl_progname);
+    _dl_exit(1);
+  };
+
+  /* Address of jump instruction to fix up */
+  instr_addr  = ((int)this_reloc->r_offset  + (int)tpnt->loadaddr);
+  got_addr = (char **) instr_addr;
+
+#ifdef DEBUG
+  _dl_fdprintf(2, "Resolving symbol %s\n",
+       strtab + symtab[symtab_index].st_name);
+#endif
+
+  /* Get the address of the GOT entry */
+  new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, 
+                       tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+  if(!new_addr) {
+    _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+              _dl_progname, strtab + symtab[symtab_index].st_name);
+    _dl_exit(1);
+  };
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+  if((unsigned int) got_addr < 0x40000000) {
+    _dl_fdprintf(2, "Calling library function: %s\n",
+              strtab + symtab[symtab_index].st_name);
+  } else {
+    *got_addr = new_addr;
+  }
+#else
+  *got_addr = new_addr;
+#endif
+  return (unsigned int) new_addr;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type){
+  int i;
+  char * strtab;
+  int reloc_type;
+  int symtab_index;
+  struct elf32_sym * symtab; 
+  struct elf32_rel * rpnt;
+  unsigned int * reloc_addr;
+
+  /* Now parse the relocation information */
+  rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof(struct elf32_rel);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i++, rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+    /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+       Make sure we do not do them again */
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+    if(symtab_index && tpnt->libtype == program_interpreter &&
+       _dl_symbol(strtab + symtab[symtab_index].st_name))
+      continue;
+
+    switch(reloc_type){
+    case R_386_NONE: break;
+    case R_386_JMP_SLOT:
+      *reloc_addr += (unsigned int) tpnt->loadaddr;
+      break;
+    default:
+      _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+      _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+      if(symtab_index) _dl_fdprintf(2, "'%s'\n",
+                                 strtab + symtab[symtab_index].st_name);
+      _dl_exit(1);
+    };
+  };
+}
+
+int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type){
+  int i;
+  char * strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym * symtab; 
+  struct elf32_rel * rpnt;
+  unsigned int * reloc_addr;
+  unsigned int symbol_addr;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof(struct elf32_rel);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i++, rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+    symbol_addr = 0;
+
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+
+    if(symtab_index) {
+
+      if(tpnt->libtype == program_interpreter && 
+        _dl_symbol(strtab + symtab[symtab_index].st_name))
+       continue;
+
+      symbol_addr = (unsigned int) 
+       _dl_find_hash(strtab + symtab[symtab_index].st_name,
+                             tpnt->symbol_scope, (int) reloc_addr, 
+                     (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0);
+
+      /*
+       * We want to allow undefined references to weak symbols - this might
+       * have been intentional.  We should not be linking local symbols
+       * here, so all bases should be covered.
+       */
+      if(!symbol_addr && 
+        ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
+       _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+                  _dl_progname, strtab + symtab[symtab_index].st_name);
+       goof++;
+      }
+    }
+    switch(reloc_type){
+    case R_386_NONE:
+      break;
+    case R_386_32:
+      *reloc_addr += symbol_addr;
+      break;
+    case R_386_PC32:
+      *reloc_addr += symbol_addr - (unsigned int) reloc_addr;
+      break;
+    case R_386_GLOB_DAT:
+    case R_386_JMP_SLOT:
+      *reloc_addr = symbol_addr;
+      break;
+    case R_386_RELATIVE:
+      *reloc_addr += (unsigned int) tpnt->loadaddr;
+      break;
+    case R_386_COPY:
+#if 0  /* Do this later */
+      _dl_fdprintf(2, "Doing copy for symbol ");
+      if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
+      _dl_fdprintf(2, "\n");
+      _dl_memcpy((void *) symtab[symtab_index].st_value,
+                (void *) symbol_addr, 
+                symtab[symtab_index].st_size);
+#endif
+      break;
+    default:
+      _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+      _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+      if (symtab_index)
+       _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
+      _dl_exit(1);
+    };
+
+  };
+  return goof;
+}
+
+
+/* This is done as a separate step, because there are cases where
+   information is first copied and later initialized.  This results in
+   the wrong information being copied.  Someone at Sun was complaining about
+   a bug in the handling of _COPY by SVr4, and this may in fact be what he
+   was talking about.  Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+   at all */
+
+int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
+       int rel_size, int type)
+{
+  int i;
+  char * strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym * symtab; 
+  struct elf32_rel * rpnt;
+  unsigned int * reloc_addr;
+  unsigned int symbol_addr;
+  struct elf_resolve *tpnt;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  tpnt = xpnt->dyn;
+  
+  rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof(struct elf32_rel);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i++, rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    if(reloc_type != R_386_COPY) continue;
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+    symbol_addr = 0;
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+    if(symtab_index) {
+
+      if(tpnt->libtype == program_interpreter && 
+        _dl_symbol(strtab + symtab[symtab_index].st_name))
+       continue;
+
+      symbol_addr = (unsigned int) 
+       _dl_find_hash(strtab + symtab[symtab_index].st_name,
+                             xpnt->next, (int) reloc_addr, NULL, 1);
+      if(!symbol_addr) {
+       _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+                  _dl_progname, strtab + symtab[symtab_index].st_name);
+       goof++;
+      };
+    };
+    if (!goof)
+      _dl_memcpy((char *) symtab[symtab_index].st_value, 
+                (char *) symbol_addr, 
+                symtab[symtab_index].st_size);
+  };
+  return goof;
+}
+
+
diff --git a/ldso/ldso/i386/ld_sysdep.h b/ldso/ldso/i386/ld_sysdep.h
new file mode 100644 (file)
index 0000000..9bbeef1
--- /dev/null
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve; \
+  GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)){           \
+       case R_386_32:          \
+         *REL += SYMBOL;               \
+         break;                \
+       case R_386_PC32:                \
+         *REL += SYMBOL - (unsigned int) REL;          \
+         break;                \
+       case R_386_GLOB_DAT:            \
+       case R_386_JMP_SLOT:            \
+         *REL = SYMBOL;                \
+         break;                \
+       case R_386_RELATIVE:            \
+         *REL += (unsigned int) LOAD;          \
+         break;                \
+       default:                \
+         _dl_exit(1);          \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START()                \
+       __asm__ volatile ("leave\n\t" \
+                   "jmp *%%eax\n\t"    \
+                   : "=a" (status) :   \
+                   "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base)  result = (n % base)
diff --git a/ldso/ldso/i386/resolve.S b/ldso/ldso/i386/resolve.S
new file mode 100644 (file)
index 0000000..db22e7b
--- /dev/null
@@ -0,0 +1,55 @@
+#if 0
+#include <sysdep.h>
+#endif
+/*
+ * These are various helper routines that are needed to run an ELF image.
+ */
+#ifndef ALIGN
+#define ALIGN 4
+#endif
+
+#ifndef NO_UNDERSCORE
+#define RUN _linux_run
+#define RESOLVE __dl_linux_resolve
+#define EXIT __interpreter_exit
+#define RESOLVER __dl_linux_resolver
+#define INIT ___loader_bootstrap
+#else
+#define RUN linux_run
+#define RESOLVE _dl_linux_resolve
+#define RESOLVER _dl_linux_resolver
+#define EXIT _interpreter_exit
+#define INIT __loader_bootstrap
+#endif
+
+.text
+.align ALIGN
+       .align 16
+
+.globl RESOLVE
+       .type   RESOLVE,@function
+RESOLVE:
+       pusha                           /* preserve all regs */
+       lea     0x20(%esp),%eax         /* eax = tpnt and reloc_entry params */
+       pushl   4(%eax)                 /* push copy of reloc_entry param */
+       pushl   (%eax)                  /* push copy of tpnt param */
+       pushl   %eax                    /* _dl_linux_resolver expects a dummy
+                                        * param - this could be removed */
+#ifdef __PIC__
+       call    .L24
+.L24:
+       popl    %ebx
+       addl    $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
+       movl RESOLVER@GOT(%ebx),%ebx    /* eax = resolved func */
+       call *%ebx
+#else
+       call RESOLVER
+#endif
+       movl    %eax,0x2C(%esp)         /* store func addr over original
+                                        * tpnt param */
+       addl    $0xC,%esp               /* remove copy parameters */
+       popa                            /* restore regs */
+       ret     $4                      /* jump to func removing original
+                                        * reloc_entry param from stack */
+.LFE2:
+       .size RESOLVE,.LFE2-RESOLVE
diff --git a/ldso/ldso/i386/sysdep.h b/ldso/ldso/i386/sysdep.h
new file mode 100644 (file)
index 0000000..9bbeef1
--- /dev/null
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve; \
+  GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)){           \
+       case R_386_32:          \
+         *REL += SYMBOL;               \
+         break;                \
+       case R_386_PC32:                \
+         *REL += SYMBOL - (unsigned int) REL;          \
+         break;                \
+       case R_386_GLOB_DAT:            \
+       case R_386_JMP_SLOT:            \
+         *REL = SYMBOL;                \
+         break;                \
+       case R_386_RELATIVE:            \
+         *REL += (unsigned int) LOAD;          \
+         break;                \
+       default:                \
+         _dl_exit(1);          \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START()                \
+       __asm__ volatile ("leave\n\t" \
+                   "jmp *%%eax\n\t"    \
+                   : "=a" (status) :   \
+                   "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base)  result = (n % base)
diff --git a/ldso/ldso/ld-uClibc.c b/ldso/ldso/ld-uClibc.c
new file mode 100644 (file)
index 0000000..6b0b864
--- /dev/null
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* Program to load an ELF binary on a linux system, and run it.
+ * References to symbols in sharable libraries can be resolved by
+ * an ELF sharable library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+/*
+ * The main trick with this program is that initially, we ourselves are not
+ * dynamicly linked.  This means that we cannot access any global variables
+ * since the GOT is initialized by the linker assuming a virtual address of 0,
+ * and we cannot call any functions since the PLT is not initialized at all
+ * (it will tend to want to call the dynamic linker
+ *
+ * There are further restrictions - we cannot use large switch statements,
+ * since the compiler generates tables of addresses and jumps through them.
+ * We can use inline functions, because these do not transfer control to
+ * a new address, but they must be static so that they are not exported
+ * from the modules.  We cannot use normal syscall stubs, because these
+ * all reference the errno global variable which is not yet initialized.
+ * We can use all of the local stack variables that we want, since these
+ * are all referenced to %ebp or %esp.
+ *
+ * Life is further complicated by the fact that initially we do not want
+ * to do a complete dynamic linking.  We want to allow the user to supply
+ * new functions replacing some of the library versions, and until we have
+ * the list of modules that we should search set up, we do not want to do
+ * any of this.  Thus I have chosen to only perform the relocations for
+ * variables that start with "_dl_" since ANSI specifies that the user is
+ * not supposed to redefine any of these variables.
+ *
+ * Fortunately, the linker itself leaves a few clues lying around, and
+ * when the kernel starts the image, there are a few further clues.
+ * First of all, there is information buried on the stack that the kernel
+ * leaves, which includes information about the load address that the
+ * program interpreter was loaded at, the number of sections, the address
+ * the application was loaded at and so forth.  Here this information
+ * is stored in the array dl_info, and the indicies are taken from the
+ * file /usr/include/sys/auxv.h on any SVr4 system.
+ *
+ * The linker itself leaves a pointer to the .dynamic section in the first
+ * slot of the GOT, and as it turns out, %ebx points to ghe GOT when
+ * you are using PIC code, so we just dereference this to get the address
+ * of the dynamic sections.
+ *
+ * Typically you must load all text pages as writable so that dynamic linking
+ * can succeed.  The kernel under SVr4 loads these as R/O, so we must call
+ * mprotect to change the protections.  Once we are done, we should set these
+ * back again, so the desired behavior is achieved.  Under linux there is
+ * currently no mprotect function in the distribution kernel (although
+ * someone has alpha patches), so for now everything is loaded writable.
+ *
+ * We do not have access to malloc and friends at the initial stages of dynamic
+ * linking, and it would be handy to have some scratchpad memory available
+ * for use as we set things up.  It is a bit of a kluge, but we mmap /dev/zero
+ * to get one page of scratchpad.  A simpleminded _dl_malloc is provided so
+ * that we have some memory that can be used for this purpose.  Typically
+ * we would not want to use the same memory pool as malloc anyway - the user
+ * might want to redefine malloc for example.
+ *
+ * Our first task is to perform a minimal linking so that we can call other
+ * portions of the dynamic linker.  Once we have done this, we then build
+ * the list of modules that the application requires, using LD_LIBRARY_PATH
+ * if this is not a suid program (/usr/lib otherwise).  Once this is done,
+ * we can do the dynamic linking as required (and we must omit the things
+ * we did to get the dynamic linker up and running in the first place.
+ * After we have done this, we just have a few housekeeping chores and we
+ * can transfer control to the user's application.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+static char * _dl_malloc_addr, *_dl_mmap_zero;
+char * _dl_library_path = 0; /* Where we look for libraries */
+char *_dl_preload = 0; /* Things to be loaded before the libs. */
+char *_dl_progname = "/lib/ld-linux-uclibc.so.1";
+static char * _dl_not_lazy = 0;
+static char * _dl_warn = 0; /* Used by ldd */
+static char * _dl_trace_loaded_objects = 0;
+static int (*_dl_elf_main)(int, char **, char**);
+
+static int (*_dl_elf_init)(void);
+
+void * (*_dl_malloc_function)(int size) = NULL;
+
+struct r_debug * _dl_debug_addr = NULL;
+
+unsigned int * _dl_brkp; 
+
+unsigned int * _dl_envp;
+
+#define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE))
+/*
+ * Make sure that the malloc buffer is aligned on 4 byte boundary.  For 64 bit
+ * platforms we may need to increase this to 8, but this is good enough for
+ * now.  This is typically called after DL_MALLOC.
+ */
+#define REALIGN() malloc_buffer = (char *) (((unsigned int) malloc_buffer + 3) & ~(3))
+
+
+
+#define ELF_HASH(RESULT,NAME) { \
+  unsigned long hash = 0; \
+    unsigned long tmp;  \
+  char * name = NAME; \
+  while (*name){  \
+    hash = (hash << 4) + *name++; \
+    if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; \
+    hash &= ~tmp; \
+  } \
+  RESULT = hash; \
+}
+extern int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct elf32_rel ELF_RELOC;
+#endif
+
+/*
+ * This stub function is used by some debuggers.  The idea is that they
+ * can set an internal breakpoint on it, so that we are notified when the
+ * address mapping is changed in some way.
+ */
+void _dl_debug_state()
+{
+  return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+  unsigned int argc;
+  char ** argv, ** envp;
+  int status;
+
+  unsigned int load_addr;
+  unsigned int * got;
+  unsigned int * aux_dat;
+  int goof = 0;
+  struct elfhdr * header;
+  struct elf_resolve * tpnt;
+  struct dyn_elf * rpnt;
+  struct elf_resolve * app_tpnt;
+  unsigned int brk_addr;
+  unsigned int dl_data[AT_EGID+1];
+  unsigned char * malloc_buffer, *mmap_zero;
+  int (*_dl_atexit)(void *);
+  int * lpnt;
+  struct dynamic * dpnt;
+  unsigned int *hash_addr;
+  struct r_debug * debug_addr;
+  unsigned int *chains;
+  int indx;
+  int _dl_secure;
+
+  /* First obtain the information on the stack that tells us more about
+     what binary is loaded, where it is loaded, etc, etc */
+
+  GET_ARGV(aux_dat, args);
+  argc = *(aux_dat - 1);
+  argv = (char **) aux_dat;
+  aux_dat += argc;  /* Skip over the argv pointers */
+  aux_dat++;  /* Skip over NULL at end of argv */
+  envp = (char **) aux_dat;
+  while(*aux_dat) aux_dat++;  /* Skip over the envp pointers */
+  aux_dat++;  /* Skip over NULL at end of envp */
+  dl_data[AT_UID] = -1; /* check later to see if it is changed */
+  while(*aux_dat)
+    {
+      unsigned int * ad1;
+      ad1 = aux_dat + 1;
+      if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+      aux_dat += 2;
+    }
+
+  /* Next, locate the GOT */
+
+  load_addr = dl_data[AT_BASE];
+
+  GET_GOT(got);
+  dpnt = (struct dynamic *) (*got + load_addr);
+  /* OK, time for another hack.  Now call mmap to get a page of writable
+     memory that can be used for a temporary malloc.  We do not know brk
+     yet, so we cannot use real malloc. */
+
+  {
+    /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+    int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+    /* See if we need to relocate this address */
+    mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+                            PROT_READ | PROT_WRITE, 
+                            MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+    if(_dl_mmap_check_error(mmap_zero)) {
+       SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n");
+       _dl_exit(13);
+    }
+  }
+
+  tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (tpnt, 0, sizeof (*tpnt));
+  app_tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (app_tpnt, 0, sizeof (*app_tpnt));
+
+  /*
+   * This is used by gdb to locate the chain of shared libraries that are currently loaded.
+   */
+  debug_addr = DL_MALLOC(sizeof(struct r_debug));
+  REALIGN();
+  _dl_memset (debug_addr, 0, sizeof (*debug_addr));
+
+  /* OK, that was easy.  Next scan the DYNAMIC section of the image.
+     We are only doing ourself right now - we will have to do the rest later */
+
+  while(dpnt->d_tag)
+    {
+      tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+      if(dpnt->d_tag == DT_TEXTREL ||
+        SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+      dpnt++;
+    }
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+    
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+      if(ppnt->p_type == PT_DYNAMIC) {
+       dpnt = (struct dynamic *) ppnt->p_vaddr;
+       while(dpnt->d_tag)
+         {
+           if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+           app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+           if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+           if(dpnt->d_tag == DT_TEXTREL ||
+              SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1;
+           dpnt++;
+         }
+      }
+  }
+
+  /* Get some more of the information that we will need to dynamicly link
+     this module to itself */
+
+  hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr);
+  tpnt->nbucket = *hash_addr++;
+  tpnt->nchain = *hash_addr++;
+  tpnt->elf_buckets = hash_addr;
+  hash_addr += tpnt->nbucket;
+  chains = hash_addr;
+
+  /* Ugly, ugly.  We need to call mprotect to change the protection of
+     the text pages so that we can do the dynamic linking.  We can set the
+     protection back again once we are done */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    /* First cover the shared library/dynamic linker. */
+    if(tpnt->dynamic_info[DT_TEXTREL]) {
+      header = (struct elfhdr *) dl_data[AT_BASE];         
+      ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+      for(i=0; i<header->e_phnum ; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+               _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+                             (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                             PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+    
+    /* Now cover the application program. */
+    if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+      ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+      for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+         _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+                      (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                      PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+  }
+
+  /* OK, now do the relocations.  We do not do a lazy binding here, so
+   that once we are done, we have considerably more flexibility. */
+
+  goof = 0;
+  for(indx=0; indx < 2; indx++)
+    {
+      int i;
+      ELF_RELOC * rpnt;
+      unsigned int * reloc_addr;
+      unsigned int symbol_addr;
+      int symtab_index;
+      unsigned int rel_addr, rel_size;
+
+  
+#ifdef ELF_USES_RELOCA
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+      if(!rel_addr) continue;
+
+      /* Now parse the relocation information */
+      rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+      for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+       reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr = 0;
+       if(symtab_index) {
+         char * strtab;
+         struct elf32_sym * symtab;
+
+         symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+         /* We only do a partial dynamic linking right now.  The user
+            is not supposed to redefine any symbols that start with
+            a '_', so we can do this with confidence. */
+
+         if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+         symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+         if(!symbol_addr) {
+           /*
+            * This will segfault - you cannot call a function until
+            * we have finished the relocations.
+            */
+           SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+           SEND_STDERR(strtab + symtab[symtab_index].st_name);
+           SEND_STDERR(" undefined.\n");
+           goof++;
+         }
+       }
+       /*
+        * Use this machine-specific macro to perform the actual relocation.
+        */
+       PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+      }
+    }
+
+  if (goof)    _dl_exit(14);
+
+  /* OK, at this point we have a crude malloc capability.  Start to build
+     the tables of the modules that are required for this beast to run.
+     We start with the basic executable, and then go from there.  Eventually
+     we will run across ourself, and we will need to properly deal with that
+     as well. */
+
+  _dl_malloc_addr = malloc_buffer;
+
+  _dl_mmap_zero = mmap_zero;
+/*  tpnt = _dl_malloc(sizeof(struct elf_resolve)); */
+
+/* Now we have done the mandatory linking of some things.  We are now
+   free to start using global variables, since these things have all been
+   fixed up by now.  Still no function calls outside of this library ,
+   since the dynamic resolver is not yet ready. */
+
+  lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr);
+  INIT_GOT(lpnt, tpnt);
+
+  /* OK, this was a big step, now we need to scan all of the user images
+     and load them properly. */
+
+  tpnt->next = 0;
+  tpnt->libname = 0;
+  tpnt->libtype = program_interpreter;
+
+  { struct elfhdr * epnt;
+    struct elf_phdr * ppnt;
+    int i;
+
+    epnt = (struct elfhdr *) dl_data[AT_BASE];
+    tpnt->n_phent = epnt->e_phnum;
+    tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff);
+    for(i=0;i < epnt->e_phnum; i++, ppnt++){
+      if(ppnt->p_type == PT_DYNAMIC) {
+       tpnt->dynamic_addr = ppnt->p_vaddr + load_addr;
+       tpnt->dynamic_size = ppnt->p_filesz;
+      }
+    }
+  }
+
+  tpnt->chains = chains;
+  tpnt->loadaddr = (char *) load_addr;
+
+  brk_addr = 0;
+  rpnt = NULL;
+
+  /* At this point we are now free to examine the user application,
+     and figure out which libraries are supposed to be called.  Until
+     we have this list, we will not be completely ready for dynamic linking */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+      if(ppnt->p_type == PT_LOAD) {
+       if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) 
+         brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+      }
+      if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+       /* make sure it's really there. */
+       if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+       /* OK, we have what we need - slip this one into the list. */
+       app_tpnt = _dl_add_elf_hash_table("", 0, 
+                           app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+       _dl_loaded_modules->libtype = elf_executable;
+       _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+       _dl_loaded_modules->n_phent = dl_data[AT_PHNUM];
+       _dl_symbol_tables = rpnt = 
+          (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+       _dl_memset (rpnt, 0, sizeof (*rpnt));
+       rpnt->dyn = _dl_loaded_modules;
+       app_tpnt->usage_count++;
+       app_tpnt->symbol_scope = _dl_symbol_tables;
+       lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]);
+#ifdef ALLOW_ZERO_PLTGOT
+       if (lpnt)
+#endif
+         INIT_GOT(lpnt, _dl_loaded_modules);
+      }
+      if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+                                        this before */
+       tpnt->libname =  _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+      }
+    }
+  }
+
+  if (argv[0])
+    _dl_progname = argv[0];
+
+  /* Now we need to figure out what kind of options are selected.
+   Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */
+  {
+    _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp);
+
+    if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+        (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+         dl_data[AT_GID] == dl_data[AT_EGID]))
+    {
+      _dl_secure = 0;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+    }
+    else
+    {
+      _dl_secure = 1;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+      _dl_unsetenv("LD_LIBRARY_PATH", envp);
+      _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+      _dl_library_path = NULL;
+    }
+  }
+
+  _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
+
+  /* OK, we now have the application in the list, and we have some
+     basic stuff in place.  Now search through the list for other shared
+     libraries that should be loaded, and insert them on the list in the
+     correct order. */
+
+#ifdef USE_CACHE
+  _dl_map_cache();
+#endif
+
+  {
+    struct elf_resolve *tcurr;
+    struct elf_resolve *tpnt1;
+    char *lpnt;
+
+    if (_dl_preload) {
+      char c, *str, *str2;
+
+      str = _dl_preload;
+      while (*str == ':' || *str == ' ' || *str == '\t')
+       str++;
+      while (*str) {
+       str2 = str;
+       while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+         str2++;
+       c = *str2;
+       *str2 = '\0';
+       if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+         tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str);
+         if (!tpnt1) {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", str);
+           else {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, str);
+             _dl_exit(15);
+           }
+         } else {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count) {
+             /* this is a real hack to make ldd not print the
+                library itself when run on a library. */
+             if (_dl_strcmp(_dl_progname, str) != 0)
+               _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+                            (unsigned)tpnt1->loadaddr);
+           }
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+       *str2 = c;
+       str = str2;
+       while (*str == ':' || *str == ' ' || *str == '\t')
+         str++;
+      }
+    }
+
+    {
+      int fd;
+      struct kernel_stat st;
+      char *preload;
+
+      if (!_dl_stat(LDSO_PRELOAD, &st)) {
+       if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+         _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, 
+                      LDSO_PRELOAD);
+       } else {
+         preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, 
+                                     MAP_PRIVATE, fd, 0);
+         _dl_close (fd);
+         if (preload == (caddr_t)-1) {
+           _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, 
+                        LDSO_PRELOAD);
+         } else {
+           char c, *cp, *cp2;
+
+           /* convert all separators and comments to spaces */
+           for (cp = preload; *cp; /*nada*/) {
+             if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+               *cp++ = ' ';
+             } else if (*cp == '#') {
+               do
+                 *cp++ = ' ';
+               while (*cp != '\n' && *cp != '\0');
+             } else {
+               cp++;
+             }
+           }
+
+           /* find start of first library */
+           for (cp = preload; *cp && *cp == ' '; cp++)
+             /*nada*/;
+
+           while (*cp) {
+             /* find end of library */
+             for (cp2 = cp; *cp && *cp != ' '; cp++)
+               /*nada*/;
+             c = *cp;
+             *cp = '\0';
+
+             tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+             if (!tpnt1) {
+               if (_dl_trace_loaded_objects)
+                 _dl_fdprintf(1, "\t%s => not found\n", cp2);
+               else {
+                 _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                              _dl_progname, cp2);
+                 _dl_exit(15);
+               }
+             } else {
+               if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+                 _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+                              (unsigned)tpnt1->loadaddr);
+                rpnt->next = 
+                 (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+               _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+               rpnt = rpnt->next;
+               tpnt1->usage_count++;
+               tpnt1->symbol_scope = _dl_symbol_tables;
+               tpnt1->libtype = elf_lib;
+               rpnt->dyn = tpnt1;
+             }
+
+             /* find start of next library */
+             *cp = c;
+             for (/*nada*/; *cp && *cp == ' '; cp++)
+               /*nada*/;
+           }
+
+           _dl_munmap(preload, st.st_size+1);
+         }
+       }
+      }
+    }
+
+    for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+    {
+      for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+      {
+       if(dpnt->d_tag == DT_NEEDED)
+       {
+         lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
+           dpnt->d_un.d_val;
+         if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0)
+         {
+           struct elf_resolve * ttmp;
+           ttmp = _dl_loaded_modules;
+           while (ttmp->next) 
+             ttmp = ttmp->next;
+           ttmp->next = tpnt;
+           tpnt->prev = ttmp;
+           tpnt->next = NULL;
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           rpnt->dyn = tpnt;
+           tpnt->usage_count++;
+           tpnt->symbol_scope = _dl_symbol_tables;
+           tpnt = NULL;
+           continue;
+         }
+         if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
+         {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", lpnt);
+           else
+           {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, lpnt);
+             _dl_exit(16);
+           }
+         }
+         else
+         {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+             _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname,
+                          (unsigned)tpnt1->loadaddr);
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+      }
+    }
+  }
+
+#ifdef USE_CACHE
+  _dl_unmap_cache();
+#endif
+
+    /* ldd uses uses this.  I am not sure how you pick up the other flags */ 
+  if(_dl_trace_loaded_objects)
+    {
+      _dl_warn = _dl_getenv("LD_WARN", envp);
+      if (!_dl_warn) _dl_exit(0);
+    }
+
+  /*
+   * If the program interpreter is not in the module chain, add it.  This will
+   * be required for dlopen to be able to access the internal functions in the 
+   * dynamic linker.
+   */
+  if(tpnt) {
+    struct elf_resolve * tcurr;
+
+    tcurr = _dl_loaded_modules;
+    if (tcurr)
+      while(tcurr->next) tcurr = tcurr->next;
+    tpnt->next = NULL;
+    tpnt->usage_count++;
+
+    if (tcurr) {
+      tcurr->next = tpnt;
+      tpnt->prev = tcurr;
+    }
+    else {
+      _dl_loaded_modules = tpnt;
+      tpnt->prev = NULL;
+    }
+    if (rpnt) {
+      rpnt->next = 
+       (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+      rpnt = rpnt->next;
+    } else {
+      rpnt =   (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt, 0, sizeof (*(rpnt->next)));
+    }
+    rpnt->dyn = tpnt;
+    tpnt = NULL;
+  }
+
+  /*
+   * OK, now all of the kids are tucked into bed in their proper addresses.
+   * Now we go through and look for REL and RELA records that indicate fixups
+   * to the GOT tables.  We need to do this in reverse order so that COPY
+   * directives work correctly */
+
+
+  goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+  /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+   and we have to manually search for entries that require fixups. 
+   Solaris gets this one right, from what I understand.  */
+
+
+  if (_dl_symbol_tables)
+    goof += _dl_copy_fixups(_dl_symbol_tables);
+
+  if(goof || _dl_trace_loaded_objects) _dl_exit(0);
+
+  /* OK, at this point things are pretty much ready to run.  Now we
+     need to touch up a few items that are required, and then
+     we can let the user application have at it.  Note that
+     the dynamic linker itself is not guaranteed to be fully
+     dynamicly linked if we are using ld.so.1, so we have to look
+     up each symbol individually. */
+
+
+  _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0);
+  if (_dl_brkp) *_dl_brkp = brk_addr;
+  _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0);
+
+  if (_dl_envp) *_dl_envp = (unsigned int) envp;
+
+  {
+    int i;
+    struct elf_phdr * ppnt;
+
+  /* We had to set the protections of all pages to R/W for dynamic linking.
+     Set text pages back to R/O */
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+      if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+        tpnt->dynamic_info[DT_TEXTREL])
+       _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+                    (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                    LXFLAGS(ppnt->p_flags));
+
+  }
+
+  _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+  /*
+   * OK, fix one more thing - set up the debug_addr structure to point
+   * to our chain.  Later we may need to fill in more fields, but this
+   * should be enough for now.
+   */
+  debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
+  debug_addr->r_version = 1;
+  debug_addr->r_ldbase = load_addr;
+  debug_addr->r_brk = (unsigned long) &_dl_debug_state;
+  _dl_debug_addr = debug_addr;
+  debug_addr->r_state = RT_CONSISTENT;
+  /* This is written in this funny way to keep gcc from inlining the
+     function call. */
+  ((void (*)(void))debug_addr->r_brk)();
+
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    {
+      /* Apparently crt1 for the application is responsible for handling this.
+       * We only need to run the init/fini for shared libraries
+       */
+      if (tpnt->libtype == program_interpreter ||
+       tpnt->libtype == elf_executable) continue;
+      if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
+      tpnt->init_flag |= INIT_FUNCS_CALLED;
+      
+      if(tpnt->dynamic_info[DT_INIT]) {
+       _dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
+                                   tpnt->dynamic_info[DT_INIT]);
+       (*_dl_elf_init)();
+      }
+      if(_dl_atexit && tpnt->dynamic_info[DT_FINI])
+      {
+        (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+      }
+#undef DL_DEBUG
+#ifdef DL_DEBUG
+      else
+      {
+       _dl_fdprintf(2, tpnt->libname);
+       _dl_fdprintf(2, ": ");
+       if (!_dl_atexit)
+         _dl_fdprintf(2, "The address is atexit () is 0x0.");
+       if (!tpnt->dynamic_info[DT_FINI])
+         _dl_fdprintf(2, "Invalid .fini section.");
+       _dl_fdprintf(2, "\n");
+      }
+#endif
+#undef DL_DEBUG
+   }
+
+  /* OK we are done here.  Turn out the lights, and lock up. */
+  _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY];
+
+
+  /*
+   * Transfer control to the application.
+   */
+  START();
+}
+
+int _dl_fixup(struct elf_resolve * tpnt)
+{
+  int goof = 0;
+  if(tpnt->next) goof += _dl_fixup(tpnt->next);
+
+  if(tpnt->dynamic_info[DT_REL]) {
+#ifdef ELF_USES_RELOCA
+    _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+    _dl_exit(17);
+#else
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+                                            tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+                                            tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+    _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+    _dl_exit(18);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_JMPREL])
+    {
+      if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
+      tpnt->init_flag |= JMP_RELOCS_DONE;
+      
+      if(! _dl_not_lazy || *_dl_not_lazy == 0)
+       _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+                                             tpnt->dynamic_info[DT_PLTRELSZ], 0);
+      else
+       goof +=  _dl_parse_relocation_information(tpnt,
+                                                 tpnt->dynamic_info[DT_JMPREL],
+                                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
+    }
+  return goof;
+}
+
+void * _dl_malloc(int size) {
+  void * retval;
+
+  if(_dl_malloc_function)
+       return (*_dl_malloc_function)(size);
+
+  if(_dl_malloc_addr-_dl_mmap_zero+size>4096) {
+       _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size,
+                               PROT_READ | PROT_WRITE, 
+                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if(_dl_mmap_check_error(_dl_mmap_zero)) {
+           _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+           _dl_exit(20);
+       }
+  }
+  retval = _dl_malloc_addr;
+  _dl_malloc_addr += size;
+
+  /*
+   * Align memory to 4 byte boundary.  Some platforms require this, others
+   * simply get better performance.
+   */
+  _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3));
+  return retval;
+}
+
+char * _dl_getenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  while ((pnt = *envp++)) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if (!*pnt || *pnt != '=' || *pnt1)
+      continue;
+    return pnt+1;
+  }
+  return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  char **newenvp = envp;
+  for (pnt = *envp; pnt; pnt = *++envp) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if(!*pnt || *pnt != '=' || *pnt1)
+      *newenvp++ = *envp;
+  }
+  *newenvp++ = *envp;
+  return;
+}
+
+char * _dl_strdup(const char * string){
+  char * retval;
+  int len;
+
+  len = _dl_strlen(string);
+  retval = _dl_malloc(len + 1);
+  _dl_strcpy(retval, string);
+  return retval;
+}
+
+/* In principle we could do the .fini stuff here, but we already
+   registered this stuff with atexit */
+int _dl_interpreter_exit(int exitcode){
+/*  _dl_fdprintf(2, "Hey, look where I am!\n"); */
+  return 0;
+}
diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h
new file mode 100644 (file)
index 0000000..2eeda2d
--- /dev/null
@@ -0,0 +1,113 @@
+#include "link.h"
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT      ((void*)-1)
+#endif
+
+struct dyn_elf{
+  unsigned int flags;
+  struct elf_resolve * dyn;
+  struct dyn_elf * next_handle;  /* Used by dlopen et al. */
+  struct dyn_elf * next;
+};
+struct elf_resolve{
+  /* These entries must be in this order to be compatible with the interface used
+     by gdb to obtain the list of symbols. */
+  char * loadaddr;
+  char * libname;
+  unsigned int dynamic_addr;
+  struct elf_resolve * next;
+  struct elf_resolve * prev;
+  /* Nothing after this address is used by gdb. */
+  enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+  struct dyn_elf * symbol_scope;
+  unsigned short usage_count;
+  unsigned short int init_flag;
+  unsigned int nbucket;
+  unsigned int * elf_buckets;
+  /*
+   * These are only used with ELF style shared libraries
+   */
+  unsigned int nchain;
+  unsigned int * chains;
+  unsigned int dynamic_info[24];
+
+  unsigned int dynamic_size;
+  unsigned int n_phent;
+  struct elf_phdr * ppnt;
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+  int r_version;
+  struct elf_resolve * link_map;
+  unsigned long brk_fun;
+  enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+  unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf     * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf    * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, 
+                                              char * loadaddr, 
+                                              unsigned int * dynamic_info, 
+                                              unsigned int dynamic_addr, 
+                                              unsigned int dynamic_size);
+extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1, 
+                           unsigned int instr_addr, 
+                           struct elf_resolve * f_tpnt, 
+                           int copyrel);
+
+extern int _dl_linux_dynamic_link(void);
+
+#ifdef __mc68000__
+/* On m68k constant strings are referenced through the GOT. */
+/* XXX Requires load_addr to be defined. */
+#define SEND_STDERR(X)                         \
+  { const char *__s = (X);                     \
+    if (__s < (const char *) load_addr) __s += load_addr;      \
+    _dl_write (2, __s, _dl_strlen (__s));      \
+  }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
+#endif
+extern int _dl_fdprintf(int, const char *, ...);
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern char * _dl_strdup(const char *);
+extern inline int _dl_symbol(char * name);
+unsigned long _dl_elf_hash(const char * name);
+
+extern inline int _dl_symbol(char * name)
+{
+  if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+    return 0;
+  return 1;
+}
+
+#define DL_ERROR_NOFILE 1
+#define DL_ERROR_NOZERO 2
+#define DL_ERROR_NOTELF 3
+#define DL_ERROR_NOTMAGIC 4
+#define DL_ERROR_NOTDYN 5
+#define DL_ERROR_MMAP_FAILED 6
+#define DL_ERROR_NODYNAMIC 7
+#define DL_WRONG_RELOCS 8
+#define DL_BAD_HANDLE 9
+#define DL_NO_SYMBOL 10
+
diff --git a/ldso/ldso/ld_string.h b/ldso/ldso/ld_string.h
new file mode 100644 (file)
index 0000000..1ea8fd7
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h>       /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char * _dl_strcpy(char * dst,const char *src)
+{
+       register char *ptr = dst;
+
+       while (*src)
+               *dst++ = *src++;
+       *dst = '\0';
+
+       return ptr;
+}
+extern inline int _dl_strcmp(const char * s1,const char * s2)
+{
+       unsigned register char c1, c2;
+
+       do {
+               c1 = (unsigned char) *s1++;
+               c2 = (unsigned char) *s2++;
+               if (c1 == '\0')
+                       return c1 - c2;
+       }
+       while (c1 == c2);
+
+       return c1 - c2;
+}
+
+extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
+{
+       unsigned register char c1 = '\0';
+       unsigned register char c2 = '\0';
+
+       while (len > 0) {
+               c1 = (unsigned char) *s1++;
+               c2 = (unsigned char) *s2++;
+               if (c1 == '\0' || c1 != c2)
+                       return c1 - c2;
+               len--;
+       }
+
+       return c1 - c2;
+}
+
+extern inline char * _dl_strchr(const char * str,int c)
+{
+       register char ch;
+
+       do {
+               if ((ch = *str) == c)
+                       return (char *) str;
+               str++;
+       }
+       while (ch);
+
+       return 0;
+}
+
+
+extern inline size_t _dl_strlen(const char * str)
+{
+       register char *ptr = (char *) str;
+
+       while (*ptr)
+               ptr++;
+       return (ptr - str);
+}
+
+extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+       register char *a = dst;
+       register const char *b = src;
+
+       while (len--)
+               *a++ = *b++;
+
+       return dst;
+}
+
+
+extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
+{
+       unsigned char *c1 = (unsigned char *)s1;
+       unsigned char *c2 = (unsigned char *)s2;
+
+       while (len--) {
+               if (*c1 != *c2) 
+                       return *c1 - *c2;
+               c1++;
+               c2++;
+       }
+       return 0;
+}
+
+extern inline void * _dl_memset(void * str,int c,size_t len)
+{
+       register char *a = str;
+
+       while (len--)
+               *a++ = c;
+
+       return str;
+}
+
+#endif
diff --git a/ldso/ldso/ld_syscall.h b/ldso/ldso/ld_syscall.h
new file mode 100644 (file)
index 0000000..3cf2443
--- /dev/null
@@ -0,0 +1,108 @@
+#include <linux/types.h>
+#include <asm/unistd.h>
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+
+#define _dl_mmap_check_error(__res)    \
+       (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+
+
+/* Here are the definitions for some syscalls that are used
+   by the dynamic linker.  The idea is that we want to be able
+   to call these before the errno symbol is dynamicly linked, so
+   we use our own version here.  Note that we cannot assume any
+   dynamic linking at all, so we cannot return any error codes.
+   We just punt if there is an error. */
+
+/* Do not include unistd.h, so gcc doesn't whine about 
+ * _exit returning.  It really doesn't return... */
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+               int flags, int fd, unsigned long offset)
+{
+       unsigned long buffer[6];
+
+       buffer[0] = (unsigned long) addr;
+       buffer[1] = (unsigned long) size;
+       buffer[2] = (unsigned long) prot;
+       buffer[3] = (unsigned long) flags;
+       buffer[4] = (unsigned long) fd;
+       buffer[5] = (unsigned long) offset;
+       return (void *) _dl_mmap_real(buffer);
+}
+
+#define __NR__dl_open __NR_open
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd, 
+           const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd, 
+           const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like.  It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define __NR__dl_stat  __NR_stat
+#define stat kernel_stat
+#define new_stat kernel_stat
+#include <asm/stat.h> 
+#undef new_stat
+#undef stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(gid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+extern inline int _dl_suid_ok(void)
+{
+    uid_t uid, euid, gid, egid;
+
+    uid = _dl_getuid();
+    euid = _dl_geteuid();
+    gid = _dl_getgid();
+    egid = _dl_getegid();
+
+    if(uid == euid && gid == egid)
+       return 1;
+    else
+       return 0;
+}
+
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
new file mode 100644 (file)
index 0000000..6b0b864
--- /dev/null
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* Program to load an ELF binary on a linux system, and run it.
+ * References to symbols in sharable libraries can be resolved by
+ * an ELF sharable library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+/*
+ * The main trick with this program is that initially, we ourselves are not
+ * dynamicly linked.  This means that we cannot access any global variables
+ * since the GOT is initialized by the linker assuming a virtual address of 0,
+ * and we cannot call any functions since the PLT is not initialized at all
+ * (it will tend to want to call the dynamic linker
+ *
+ * There are further restrictions - we cannot use large switch statements,
+ * since the compiler generates tables of addresses and jumps through them.
+ * We can use inline functions, because these do not transfer control to
+ * a new address, but they must be static so that they are not exported
+ * from the modules.  We cannot use normal syscall stubs, because these
+ * all reference the errno global variable which is not yet initialized.
+ * We can use all of the local stack variables that we want, since these
+ * are all referenced to %ebp or %esp.
+ *
+ * Life is further complicated by the fact that initially we do not want
+ * to do a complete dynamic linking.  We want to allow the user to supply
+ * new functions replacing some of the library versions, and until we have
+ * the list of modules that we should search set up, we do not want to do
+ * any of this.  Thus I have chosen to only perform the relocations for
+ * variables that start with "_dl_" since ANSI specifies that the user is
+ * not supposed to redefine any of these variables.
+ *
+ * Fortunately, the linker itself leaves a few clues lying around, and
+ * when the kernel starts the image, there are a few further clues.
+ * First of all, there is information buried on the stack that the kernel
+ * leaves, which includes information about the load address that the
+ * program interpreter was loaded at, the number of sections, the address
+ * the application was loaded at and so forth.  Here this information
+ * is stored in the array dl_info, and the indicies are taken from the
+ * file /usr/include/sys/auxv.h on any SVr4 system.
+ *
+ * The linker itself leaves a pointer to the .dynamic section in the first
+ * slot of the GOT, and as it turns out, %ebx points to ghe GOT when
+ * you are using PIC code, so we just dereference this to get the address
+ * of the dynamic sections.
+ *
+ * Typically you must load all text pages as writable so that dynamic linking
+ * can succeed.  The kernel under SVr4 loads these as R/O, so we must call
+ * mprotect to change the protections.  Once we are done, we should set these
+ * back again, so the desired behavior is achieved.  Under linux there is
+ * currently no mprotect function in the distribution kernel (although
+ * someone has alpha patches), so for now everything is loaded writable.
+ *
+ * We do not have access to malloc and friends at the initial stages of dynamic
+ * linking, and it would be handy to have some scratchpad memory available
+ * for use as we set things up.  It is a bit of a kluge, but we mmap /dev/zero
+ * to get one page of scratchpad.  A simpleminded _dl_malloc is provided so
+ * that we have some memory that can be used for this purpose.  Typically
+ * we would not want to use the same memory pool as malloc anyway - the user
+ * might want to redefine malloc for example.
+ *
+ * Our first task is to perform a minimal linking so that we can call other
+ * portions of the dynamic linker.  Once we have done this, we then build
+ * the list of modules that the application requires, using LD_LIBRARY_PATH
+ * if this is not a suid program (/usr/lib otherwise).  Once this is done,
+ * we can do the dynamic linking as required (and we must omit the things
+ * we did to get the dynamic linker up and running in the first place.
+ * After we have done this, we just have a few housekeeping chores and we
+ * can transfer control to the user's application.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+static char * _dl_malloc_addr, *_dl_mmap_zero;
+char * _dl_library_path = 0; /* Where we look for libraries */
+char *_dl_preload = 0; /* Things to be loaded before the libs. */
+char *_dl_progname = "/lib/ld-linux-uclibc.so.1";
+static char * _dl_not_lazy = 0;
+static char * _dl_warn = 0; /* Used by ldd */
+static char * _dl_trace_loaded_objects = 0;
+static int (*_dl_elf_main)(int, char **, char**);
+
+static int (*_dl_elf_init)(void);
+
+void * (*_dl_malloc_function)(int size) = NULL;
+
+struct r_debug * _dl_debug_addr = NULL;
+
+unsigned int * _dl_brkp; 
+
+unsigned int * _dl_envp;
+
+#define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE))
+/*
+ * Make sure that the malloc buffer is aligned on 4 byte boundary.  For 64 bit
+ * platforms we may need to increase this to 8, but this is good enough for
+ * now.  This is typically called after DL_MALLOC.
+ */
+#define REALIGN() malloc_buffer = (char *) (((unsigned int) malloc_buffer + 3) & ~(3))
+
+
+
+#define ELF_HASH(RESULT,NAME) { \
+  unsigned long hash = 0; \
+    unsigned long tmp;  \
+  char * name = NAME; \
+  while (*name){  \
+    hash = (hash << 4) + *name++; \
+    if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; \
+    hash &= ~tmp; \
+  } \
+  RESULT = hash; \
+}
+extern int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct elf32_rel ELF_RELOC;
+#endif
+
+/*
+ * This stub function is used by some debuggers.  The idea is that they
+ * can set an internal breakpoint on it, so that we are notified when the
+ * address mapping is changed in some way.
+ */
+void _dl_debug_state()
+{
+  return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+  unsigned int argc;
+  char ** argv, ** envp;
+  int status;
+
+  unsigned int load_addr;
+  unsigned int * got;
+  unsigned int * aux_dat;
+  int goof = 0;
+  struct elfhdr * header;
+  struct elf_resolve * tpnt;
+  struct dyn_elf * rpnt;
+  struct elf_resolve * app_tpnt;
+  unsigned int brk_addr;
+  unsigned int dl_data[AT_EGID+1];
+  unsigned char * malloc_buffer, *mmap_zero;
+  int (*_dl_atexit)(void *);
+  int * lpnt;
+  struct dynamic * dpnt;
+  unsigned int *hash_addr;
+  struct r_debug * debug_addr;
+  unsigned int *chains;
+  int indx;
+  int _dl_secure;
+
+  /* First obtain the information on the stack that tells us more about
+     what binary is loaded, where it is loaded, etc, etc */
+
+  GET_ARGV(aux_dat, args);
+  argc = *(aux_dat - 1);
+  argv = (char **) aux_dat;
+  aux_dat += argc;  /* Skip over the argv pointers */
+  aux_dat++;  /* Skip over NULL at end of argv */
+  envp = (char **) aux_dat;
+  while(*aux_dat) aux_dat++;  /* Skip over the envp pointers */
+  aux_dat++;  /* Skip over NULL at end of envp */
+  dl_data[AT_UID] = -1; /* check later to see if it is changed */
+  while(*aux_dat)
+    {
+      unsigned int * ad1;
+      ad1 = aux_dat + 1;
+      if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+      aux_dat += 2;
+    }
+
+  /* Next, locate the GOT */
+
+  load_addr = dl_data[AT_BASE];
+
+  GET_GOT(got);
+  dpnt = (struct dynamic *) (*got + load_addr);
+  /* OK, time for another hack.  Now call mmap to get a page of writable
+     memory that can be used for a temporary malloc.  We do not know brk
+     yet, so we cannot use real malloc. */
+
+  {
+    /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+    int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+    /* See if we need to relocate this address */
+    mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+                            PROT_READ | PROT_WRITE, 
+                            MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+    if(_dl_mmap_check_error(mmap_zero)) {
+       SEND_STDERR("dl_boot: mmap of /dev/zero failed!\n");
+       _dl_exit(13);
+    }
+  }
+
+  tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (tpnt, 0, sizeof (*tpnt));
+  app_tpnt = DL_MALLOC(sizeof(struct elf_resolve));
+  REALIGN();
+  _dl_memset (app_tpnt, 0, sizeof (*app_tpnt));
+
+  /*
+   * This is used by gdb to locate the chain of shared libraries that are currently loaded.
+   */
+  debug_addr = DL_MALLOC(sizeof(struct r_debug));
+  REALIGN();
+  _dl_memset (debug_addr, 0, sizeof (*debug_addr));
+
+  /* OK, that was easy.  Next scan the DYNAMIC section of the image.
+     We are only doing ourself right now - we will have to do the rest later */
+
+  while(dpnt->d_tag)
+    {
+      tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+      if(dpnt->d_tag == DT_TEXTREL ||
+        SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+      dpnt++;
+    }
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+    
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+      if(ppnt->p_type == PT_DYNAMIC) {
+       dpnt = (struct dynamic *) ppnt->p_vaddr;
+       while(dpnt->d_tag)
+         {
+           if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+           app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+           if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+           if(dpnt->d_tag == DT_TEXTREL ||
+              SVR4_BUGCOMPAT) app_tpnt->dynamic_info[DT_TEXTREL] = 1;
+           dpnt++;
+         }
+      }
+  }
+
+  /* Get some more of the information that we will need to dynamicly link
+     this module to itself */
+
+  hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr);
+  tpnt->nbucket = *hash_addr++;
+  tpnt->nchain = *hash_addr++;
+  tpnt->elf_buckets = hash_addr;
+  hash_addr += tpnt->nbucket;
+  chains = hash_addr;
+
+  /* Ugly, ugly.  We need to call mprotect to change the protection of
+     the text pages so that we can do the dynamic linking.  We can set the
+     protection back again once we are done */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    /* First cover the shared library/dynamic linker. */
+    if(tpnt->dynamic_info[DT_TEXTREL]) {
+      header = (struct elfhdr *) dl_data[AT_BASE];         
+      ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+      for(i=0; i<header->e_phnum ; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+               _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+                             (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                             PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+    
+    /* Now cover the application program. */
+    if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+      ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+      for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+       if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+         _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+                      (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                      PROT_READ | PROT_WRITE | PROT_EXEC);
+      }
+    }
+  }
+
+  /* OK, now do the relocations.  We do not do a lazy binding here, so
+   that once we are done, we have considerably more flexibility. */
+
+  goof = 0;
+  for(indx=0; indx < 2; indx++)
+    {
+      int i;
+      ELF_RELOC * rpnt;
+      unsigned int * reloc_addr;
+      unsigned int symbol_addr;
+      int symtab_index;
+      unsigned int rel_addr, rel_size;
+
+  
+#ifdef ELF_USES_RELOCA
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+      rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+      rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+      if(!rel_addr) continue;
+
+      /* Now parse the relocation information */
+      rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+      for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+       reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr = 0;
+       if(symtab_index) {
+         char * strtab;
+         struct elf32_sym * symtab;
+
+         symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+         strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+         /* We only do a partial dynamic linking right now.  The user
+            is not supposed to redefine any symbols that start with
+            a '_', so we can do this with confidence. */
+
+         if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+         symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+         if(!symbol_addr) {
+           /*
+            * This will segfault - you cannot call a function until
+            * we have finished the relocations.
+            */
+           SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+           SEND_STDERR(strtab + symtab[symtab_index].st_name);
+           SEND_STDERR(" undefined.\n");
+           goof++;
+         }
+       }
+       /*
+        * Use this machine-specific macro to perform the actual relocation.
+        */
+       PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+      }
+    }
+
+  if (goof)    _dl_exit(14);
+
+  /* OK, at this point we have a crude malloc capability.  Start to build
+     the tables of the modules that are required for this beast to run.
+     We start with the basic executable, and then go from there.  Eventually
+     we will run across ourself, and we will need to properly deal with that
+     as well. */
+
+  _dl_malloc_addr = malloc_buffer;
+
+  _dl_mmap_zero = mmap_zero;
+/*  tpnt = _dl_malloc(sizeof(struct elf_resolve)); */
+
+/* Now we have done the mandatory linking of some things.  We are now
+   free to start using global variables, since these things have all been
+   fixed up by now.  Still no function calls outside of this library ,
+   since the dynamic resolver is not yet ready. */
+
+  lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr);
+  INIT_GOT(lpnt, tpnt);
+
+  /* OK, this was a big step, now we need to scan all of the user images
+     and load them properly. */
+
+  tpnt->next = 0;
+  tpnt->libname = 0;
+  tpnt->libtype = program_interpreter;
+
+  { struct elfhdr * epnt;
+    struct elf_phdr * ppnt;
+    int i;
+
+    epnt = (struct elfhdr *) dl_data[AT_BASE];
+    tpnt->n_phent = epnt->e_phnum;
+    tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + epnt->e_phoff);
+    for(i=0;i < epnt->e_phnum; i++, ppnt++){
+      if(ppnt->p_type == PT_DYNAMIC) {
+       tpnt->dynamic_addr = ppnt->p_vaddr + load_addr;
+       tpnt->dynamic_size = ppnt->p_filesz;
+      }
+    }
+  }
+
+  tpnt->chains = chains;
+  tpnt->loadaddr = (char *) load_addr;
+
+  brk_addr = 0;
+  rpnt = NULL;
+
+  /* At this point we are now free to examine the user application,
+     and figure out which libraries are supposed to be called.  Until
+     we have this list, we will not be completely ready for dynamic linking */
+
+  {
+    struct elf_phdr * ppnt;
+    int i;
+
+    ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+      if(ppnt->p_type == PT_LOAD) {
+       if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) 
+         brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+      }
+      if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+       /* make sure it's really there. */
+       if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+       /* OK, we have what we need - slip this one into the list. */
+       app_tpnt = _dl_add_elf_hash_table("", 0, 
+                           app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+       _dl_loaded_modules->libtype = elf_executable;
+       _dl_loaded_modules->ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+       _dl_loaded_modules->n_phent = dl_data[AT_PHNUM];
+       _dl_symbol_tables = rpnt = 
+          (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+       _dl_memset (rpnt, 0, sizeof (*rpnt));
+       rpnt->dyn = _dl_loaded_modules;
+       app_tpnt->usage_count++;
+       app_tpnt->symbol_scope = _dl_symbol_tables;
+       lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]);
+#ifdef ALLOW_ZERO_PLTGOT
+       if (lpnt)
+#endif
+         INIT_GOT(lpnt, _dl_loaded_modules);
+      }
+      if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+                                        this before */
+       tpnt->libname =  _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+      }
+    }
+  }
+
+  if (argv[0])
+    _dl_progname = argv[0];
+
+  /* Now we need to figure out what kind of options are selected.
+   Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */
+  {
+    _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp);
+
+    if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+        (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+         dl_data[AT_GID] == dl_data[AT_EGID]))
+    {
+      _dl_secure = 0;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+    }
+    else
+    {
+      _dl_secure = 1;
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+      _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+      _dl_unsetenv("LD_LIBRARY_PATH", envp);
+      _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+      _dl_library_path = NULL;
+    }
+  }
+
+  _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
+
+  /* OK, we now have the application in the list, and we have some
+     basic stuff in place.  Now search through the list for other shared
+     libraries that should be loaded, and insert them on the list in the
+     correct order. */
+
+#ifdef USE_CACHE
+  _dl_map_cache();
+#endif
+
+  {
+    struct elf_resolve *tcurr;
+    struct elf_resolve *tpnt1;
+    char *lpnt;
+
+    if (_dl_preload) {
+      char c, *str, *str2;
+
+      str = _dl_preload;
+      while (*str == ':' || *str == ' ' || *str == '\t')
+       str++;
+      while (*str) {
+       str2 = str;
+       while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+         str2++;
+       c = *str2;
+       *str2 = '\0';
+       if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+         tpnt1 = _dl_load_shared_library(_dl_secure, NULL, str);
+         if (!tpnt1) {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", str);
+           else {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, str);
+             _dl_exit(15);
+           }
+         } else {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count) {
+             /* this is a real hack to make ldd not print the
+                library itself when run on a library. */
+             if (_dl_strcmp(_dl_progname, str) != 0)
+               _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+                            (unsigned)tpnt1->loadaddr);
+           }
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+       *str2 = c;
+       str = str2;
+       while (*str == ':' || *str == ' ' || *str == '\t')
+         str++;
+      }
+    }
+
+    {
+      int fd;
+      struct kernel_stat st;
+      char *preload;
+
+      if (!_dl_stat(LDSO_PRELOAD, &st)) {
+       if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+         _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname, 
+                      LDSO_PRELOAD);
+       } else {
+         preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE, 
+                                     MAP_PRIVATE, fd, 0);
+         _dl_close (fd);
+         if (preload == (caddr_t)-1) {
+           _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname, 
+                        LDSO_PRELOAD);
+         } else {
+           char c, *cp, *cp2;
+
+           /* convert all separators and comments to spaces */
+           for (cp = preload; *cp; /*nada*/) {
+             if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+               *cp++ = ' ';
+             } else if (*cp == '#') {
+               do
+                 *cp++ = ' ';
+               while (*cp != '\n' && *cp != '\0');
+             } else {
+               cp++;
+             }
+           }
+
+           /* find start of first library */
+           for (cp = preload; *cp && *cp == ' '; cp++)
+             /*nada*/;
+
+           while (*cp) {
+             /* find end of library */
+             for (cp2 = cp; *cp && *cp != ' '; cp++)
+               /*nada*/;
+             c = *cp;
+             *cp = '\0';
+
+             tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+             if (!tpnt1) {
+               if (_dl_trace_loaded_objects)
+                 _dl_fdprintf(1, "\t%s => not found\n", cp2);
+               else {
+                 _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                              _dl_progname, cp2);
+                 _dl_exit(15);
+               }
+             } else {
+               if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+                 _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+                              (unsigned)tpnt1->loadaddr);
+                rpnt->next = 
+                 (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+               _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+               rpnt = rpnt->next;
+               tpnt1->usage_count++;
+               tpnt1->symbol_scope = _dl_symbol_tables;
+               tpnt1->libtype = elf_lib;
+               rpnt->dyn = tpnt1;
+             }
+
+             /* find start of next library */
+             *cp = c;
+             for (/*nada*/; *cp && *cp == ' '; cp++)
+               /*nada*/;
+           }
+
+           _dl_munmap(preload, st.st_size+1);
+         }
+       }
+      }
+    }
+
+    for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+    {
+      for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+      {
+       if(dpnt->d_tag == DT_NEEDED)
+       {
+         lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
+           dpnt->d_un.d_val;
+         if (tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0)
+         {
+           struct elf_resolve * ttmp;
+           ttmp = _dl_loaded_modules;
+           while (ttmp->next) 
+             ttmp = ttmp->next;
+           ttmp->next = tpnt;
+           tpnt->prev = ttmp;
+           tpnt->next = NULL;
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           rpnt->dyn = tpnt;
+           tpnt->usage_count++;
+           tpnt->symbol_scope = _dl_symbol_tables;
+           tpnt = NULL;
+           continue;
+         }
+         if (!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
+         {
+           if (_dl_trace_loaded_objects)
+             _dl_fdprintf(1, "\t%s => not found\n", lpnt);
+           else
+           {
+             _dl_fdprintf(2, "%s: can't load library '%s'\n",
+                          _dl_progname, lpnt);
+             _dl_exit(16);
+           }
+         }
+         else
+         {
+           if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+             _dl_fdprintf(1, "\t%s => %s (0x%x)\n", lpnt, tpnt1->libname,
+                          (unsigned)tpnt1->loadaddr);
+           rpnt->next = 
+             (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+           _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+           rpnt = rpnt->next;
+           tpnt1->usage_count++;
+           tpnt1->symbol_scope = _dl_symbol_tables;
+           tpnt1->libtype = elf_lib;
+           rpnt->dyn = tpnt1;
+         }
+       }
+      }
+    }
+  }
+
+#ifdef USE_CACHE
+  _dl_unmap_cache();
+#endif
+
+    /* ldd uses uses this.  I am not sure how you pick up the other flags */ 
+  if(_dl_trace_loaded_objects)
+    {
+      _dl_warn = _dl_getenv("LD_WARN", envp);
+      if (!_dl_warn) _dl_exit(0);
+    }
+
+  /*
+   * If the program interpreter is not in the module chain, add it.  This will
+   * be required for dlopen to be able to access the internal functions in the 
+   * dynamic linker.
+   */
+  if(tpnt) {
+    struct elf_resolve * tcurr;
+
+    tcurr = _dl_loaded_modules;
+    if (tcurr)
+      while(tcurr->next) tcurr = tcurr->next;
+    tpnt->next = NULL;
+    tpnt->usage_count++;
+
+    if (tcurr) {
+      tcurr->next = tpnt;
+      tpnt->prev = tcurr;
+    }
+    else {
+      _dl_loaded_modules = tpnt;
+      tpnt->prev = NULL;
+    }
+    if (rpnt) {
+      rpnt->next = 
+       (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+      rpnt = rpnt->next;
+    } else {
+      rpnt =   (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+      _dl_memset (rpnt, 0, sizeof (*(rpnt->next)));
+    }
+    rpnt->dyn = tpnt;
+    tpnt = NULL;
+  }
+
+  /*
+   * OK, now all of the kids are tucked into bed in their proper addresses.
+   * Now we go through and look for REL and RELA records that indicate fixups
+   * to the GOT tables.  We need to do this in reverse order so that COPY
+   * directives work correctly */
+
+
+  goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+  /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+   and we have to manually search for entries that require fixups. 
+   Solaris gets this one right, from what I understand.  */
+
+
+  if (_dl_symbol_tables)
+    goof += _dl_copy_fixups(_dl_symbol_tables);
+
+  if(goof || _dl_trace_loaded_objects) _dl_exit(0);
+
+  /* OK, at this point things are pretty much ready to run.  Now we
+     need to touch up a few items that are required, and then
+     we can let the user application have at it.  Note that
+     the dynamic linker itself is not guaranteed to be fully
+     dynamicly linked if we are using ld.so.1, so we have to look
+     up each symbol individually. */
+
+
+  _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0);
+  if (_dl_brkp) *_dl_brkp = brk_addr;
+  _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0);
+
+  if (_dl_envp) *_dl_envp = (unsigned int) envp;
+
+  {
+    int i;
+    struct elf_phdr * ppnt;
+
+  /* We had to set the protections of all pages to R/W for dynamic linking.
+     Set text pages back to R/O */
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+      if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+        tpnt->dynamic_info[DT_TEXTREL])
+       _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+                    (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                    LXFLAGS(ppnt->p_flags));
+
+  }
+
+  _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+  /*
+   * OK, fix one more thing - set up the debug_addr structure to point
+   * to our chain.  Later we may need to fill in more fields, but this
+   * should be enough for now.
+   */
+  debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
+  debug_addr->r_version = 1;
+  debug_addr->r_ldbase = load_addr;
+  debug_addr->r_brk = (unsigned long) &_dl_debug_state;
+  _dl_debug_addr = debug_addr;
+  debug_addr->r_state = RT_CONSISTENT;
+  /* This is written in this funny way to keep gcc from inlining the
+     function call. */
+  ((void (*)(void))debug_addr->r_brk)();
+
+  for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+    {
+      /* Apparently crt1 for the application is responsible for handling this.
+       * We only need to run the init/fini for shared libraries
+       */
+      if (tpnt->libtype == program_interpreter ||
+       tpnt->libtype == elf_executable) continue;
+      if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
+      tpnt->init_flag |= INIT_FUNCS_CALLED;
+      
+      if(tpnt->dynamic_info[DT_INIT]) {
+       _dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
+                                   tpnt->dynamic_info[DT_INIT]);
+       (*_dl_elf_init)();
+      }
+      if(_dl_atexit && tpnt->dynamic_info[DT_FINI])
+      {
+        (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+      }
+#undef DL_DEBUG
+#ifdef DL_DEBUG
+      else
+      {
+       _dl_fdprintf(2, tpnt->libname);
+       _dl_fdprintf(2, ": ");
+       if (!_dl_atexit)
+         _dl_fdprintf(2, "The address is atexit () is 0x0.");
+       if (!tpnt->dynamic_info[DT_FINI])
+         _dl_fdprintf(2, "Invalid .fini section.");
+       _dl_fdprintf(2, "\n");
+      }
+#endif
+#undef DL_DEBUG
+   }
+
+  /* OK we are done here.  Turn out the lights, and lock up. */
+  _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY];
+
+
+  /*
+   * Transfer control to the application.
+   */
+  START();
+}
+
+int _dl_fixup(struct elf_resolve * tpnt)
+{
+  int goof = 0;
+  if(tpnt->next) goof += _dl_fixup(tpnt->next);
+
+  if(tpnt->dynamic_info[DT_REL]) {
+#ifdef ELF_USES_RELOCA
+    _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+    _dl_exit(17);
+#else
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+                                            tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+                                            tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+    _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+    _dl_exit(18);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_JMPREL])
+    {
+      if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
+      tpnt->init_flag |= JMP_RELOCS_DONE;
+      
+      if(! _dl_not_lazy || *_dl_not_lazy == 0)
+       _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+                                             tpnt->dynamic_info[DT_PLTRELSZ], 0);
+      else
+       goof +=  _dl_parse_relocation_information(tpnt,
+                                                 tpnt->dynamic_info[DT_JMPREL],
+                                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
+    }
+  return goof;
+}
+
+void * _dl_malloc(int size) {
+  void * retval;
+
+  if(_dl_malloc_function)
+       return (*_dl_malloc_function)(size);
+
+  if(_dl_malloc_addr-_dl_mmap_zero+size>4096) {
+       _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size,
+                               PROT_READ | PROT_WRITE, 
+                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       if(_dl_mmap_check_error(_dl_mmap_zero)) {
+           _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+           _dl_exit(20);
+       }
+  }
+  retval = _dl_malloc_addr;
+  _dl_malloc_addr += size;
+
+  /*
+   * Align memory to 4 byte boundary.  Some platforms require this, others
+   * simply get better performance.
+   */
+  _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3));
+  return retval;
+}
+
+char * _dl_getenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  while ((pnt = *envp++)) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if (!*pnt || *pnt != '=' || *pnt1)
+      continue;
+    return pnt+1;
+  }
+  return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+  char *pnt;
+  char *pnt1;
+  char **newenvp = envp;
+  for (pnt = *envp; pnt; pnt = *++envp) {
+    pnt1 = symbol;
+    while (*pnt && *pnt == *pnt1)
+      pnt1++, pnt++;
+    if(!*pnt || *pnt != '=' || *pnt1)
+      *newenvp++ = *envp;
+  }
+  *newenvp++ = *envp;
+  return;
+}
+
+char * _dl_strdup(const char * string){
+  char * retval;
+  int len;
+
+  len = _dl_strlen(string);
+  retval = _dl_malloc(len + 1);
+  _dl_strcpy(retval, string);
+  return retval;
+}
+
+/* In principle we could do the .fini stuff here, but we already
+   registered this stuff with atexit */
+int _dl_interpreter_exit(int exitcode){
+/*  _dl_fdprintf(2, "Hey, look where I am!\n"); */
+  return 0;
+}
diff --git a/ldso/ldso/link.h b/ldso/ldso/link.h
new file mode 100644 (file)
index 0000000..adaa20e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _LINK_H
+#define _LINK_H
+
+#include "elf.h"
+
+/* Header file that describes the internal data structures used by the
+ * ELF dynamic linker.  */
+
+struct link_map
+{
+  /* These entries must be in this order to be compatible with the
+   * interface used by gdb to obtain the list of symbols. */
+  unsigned long l_addr;        /* address at which object is mapped */
+  char *l_name;                /* full name of loaded object */
+  Elf32_Dyn *l_ld;     /* dynamic structure of object */
+  struct link_map *l_next;
+  struct link_map *l_prev;
+};
+
+/* The DT_DEBUG entry in the .dynamic section is given the address of
+ * this structure. gdb can pick this up to obtain the correct list of
+ * loaded modules. */
+struct r_debug
+{
+  int r_version;               /* debugging info version no */
+  struct link_map *r_map;      /* address of link_map */
+  unsigned long r_brk;         /* address of update routine */
+  enum
+  {
+    RT_CONSISTENT,
+    RT_ADD,
+    RT_DELETE
+  } r_state;
+  unsigned long r_ldbase;      /* base addr of ld.so */
+};
+
+#endif /* _LINK_H */
diff --git a/ldso/ldso/linuxelf.h b/ldso/ldso/linuxelf.h
new file mode 100644 (file)
index 0000000..cc016f6
--- /dev/null
@@ -0,0 +1,137 @@
+/* This should eventually appear in the distribution version of linux/elf.h */
+#ifndef R_SPARC_NONE
+#define R_SPARC_NONE           0
+#define R_SPARC_8              1
+#define R_SPARC_16             2
+#define R_SPARC_32             3
+#define R_SPARC_DISP8          4
+#define R_SPARC_DISP16         5
+#define R_SPARC_DISP32         6
+#define R_SPARC_WDISP30                7
+#define R_SPARC_WDISP22                8
+#define R_SPARC_HI22           9
+#define R_SPARC_22             10
+#define R_SPARC_13             11
+#define R_SPARC_LO10           12
+#define R_SPARC_GOT10          13
+#define R_SPARC_GOT13          14
+#define R_SPARC_GOT22          15
+#define R_SPARC_PC10           16
+#define R_SPARC_PC22           17
+#define R_SPARC_WPLT30         18
+#define R_SPARC_COPY           19
+#define R_SPARC_GLOB_DAT       20
+#define R_SPARC_JMP_SLOT       21
+#define R_SPARC_RELATIVE       22
+#define R_SPARC_UA32           23
+#endif
+
+#ifndef R_68K_NONE
+#define R_68K_NONE     0
+#define R_68K_32       1
+#define R_68K_16       2
+#define R_68K_8                3
+#define R_68K_PC32     4
+#define R_68K_PC16     5
+#define R_68K_PC8      6
+#define R_68K_GOT32    7
+#define R_68K_GOT16    8
+#define R_68K_GOT8     9
+#define R_68K_GOT32O   10
+#define R_68K_GOT16O   11
+#define R_68K_GOT8O    12
+#define R_68K_PLT32    13
+#define R_68K_PLT16    14
+#define R_68K_PLT8     15
+#define R_68K_PLT32O   16
+#define R_68K_PLT16O   17
+#define R_68K_PLT8O    18
+#define R_68K_COPY     19
+#define R_68K_GLOB_DAT 20
+#define R_68K_JMP_SLOT 21
+#define R_68K_RELATIVE 22
+#define R_68K_NUM      23
+#endif
+
+/*
+ * These constants define the elements of the auxiliary vector used to
+ * pass additional information from the kernel to an ELF application.
+ */
+
+#ifndef AT_NULL
+typedef struct
+{
+  int  a_type;
+  union{
+    long a_val;
+    void *p_ptr;
+    void (*a_fcn)();
+  } a_un;
+} auxv_t;
+
+/*
+ * Values of a_type... These often appear in the file /usr/include/sys/auxv.h
+ * on SVr4 systems.
+ */
+#define AT_NULL                0
+#define AT_IGNORE      1
+#define AT_EXECFD      2
+#define AT_PHDR                3
+#define AT_PHENT       4
+#define AT_PHNUM       5
+#define AT_PAGESZ      6
+#define AT_BASE                7
+#define AT_FLAGS               8
+#define AT_ENTRY       9
+#endif
+#ifndef AT_NOTELF
+#define AT_NOTELF 10   /* program is not ELF */
+#define AT_UID    11   /* real uid */
+#define AT_EUID   12   /* effective uid */
+#define AT_GID    13   /* real gid */
+#define AT_EGID   14   /* effective gid */
+#endif
+
+extern int _dl_linux_resolve(void);
+extern struct elf_resolve * _dl_load_shared_library(int secure, 
+                               struct elf_resolve *, char * libname);
+extern void * _dl_malloc(int size);
+extern int _dl_map_cache(void);
+extern int _dl_unmap_cache(void);
+
+extern struct elf_resolve * _dl_load_elf_shared_library(int secure, 
+                               char * libname, int);
+int _dl_copy_fixups(struct dyn_elf * tpnt);
+
+extern int linux_run(int argc, char * argv[]);
+
+extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type);
+
+extern int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type);
+extern int _dl_parse_copy_information(struct dyn_elf * rpnt, int rel_addr,
+       int rel_size, int type);
+
+
+/* This means that we may be forced to manually search for copy fixups
+   which were omitted by the linker.  We cannot depend upon the DT_TEXTREL
+   to tell us whether there are fixups in a text section or not. */
+
+#ifndef SVR4_BUGCOMPAT
+#define SVR4_BUGCOMPAT 1
+#endif
+
+#ifndef PF_R
+#define PF_R 4
+#define PF_W 2
+#define PF_X 1
+#endif
+
+/* Convert between the Linux flags for page protections and the
+   ones specified in the ELF standard. */
+
+#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
+                   (((X) & PF_W) ? PROT_WRITE : 0) | \
+                   (((X) & PF_X) ? PROT_EXEC : 0))
+
diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h
new file mode 100644 (file)
index 0000000..24af47c
--- /dev/null
@@ -0,0 +1,87 @@
+
+/* Various assmbly language/system dependent hacks that are required
+   so that we can minimize the amount of platform specific code. */
+
+/* Define this if the system uses RELOCA.  */
+#define ELF_USES_RELOCA
+
+/* Get a pointer to the argv array.  On many platforms this can be
+   just the address if the first argument, on other platforms we need
+   to do something a little more subtle here.  */
+#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
+
+/* Get the address of the Global offset table.  This must be absolute,
+   not relative.  */
+#define GET_GOT(X)     __asm__ ("movel %%a5,%0" : "=g" (X))
+
+/* Initialization sequence for a GOT.  */
+#define INIT_GOT(GOT_BASE,MODULE)              \
+{                                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve;       \
+  GOT_BASE[1] = (int) (MODULE);                        \
+}
+
+/* Here is a macro to perform a relocation.  This is only used when
+   bootstrapping the dynamic loader.  RELP is the relocation that we
+   are performing, REL is the pointer to the address we are
+   relocating.  SYMBOL is the symbol involved in the relocation, and
+   LOAD is the load address. */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)          \
+  switch (ELF32_R_TYPE ((RELP)->r_info))                       \
+    {                                                          \
+    case R_68K_8:                                              \
+      *(char *) (REL) = (SYMBOL) + (RELP)->r_addend;           \
+      break;                                                   \
+    case R_68K_16:                                             \
+      *(short *) (REL) = (SYMBOL) + (RELP)->r_addend;          \
+      break;                                                   \
+    case R_68K_32:                                             \
+      *(REL) = (SYMBOL) + (RELP)->r_addend;                    \
+      break;                                                   \
+    case R_68K_PC8:                                            \
+      *(char *) (REL) = ((SYMBOL) + (RELP)->r_addend           \
+                        - (unsigned int) (REL));               \
+      break;                                                   \
+    case R_68K_PC16:                                           \
+      *(short *) (REL) = ((SYMBOL) + (RELP)->r_addend          \
+                         - (unsigned int) (REL));              \
+      break;                                                   \
+    case R_68K_PC32:                                           \
+      *(REL) = ((SYMBOL) + (RELP)->r_addend                    \
+               - (unsigned int) (REL));                        \
+      break;                                                   \
+    case R_68K_GLOB_DAT:                                       \
+    case R_68K_JMP_SLOT:                                       \
+      *(REL) = (SYMBOL);                                       \
+      break;                                                   \
+    case R_68K_RELATIVE:               /* Compatibility kludge */ \
+      *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+      break;                                                   \
+    default:                                                   \
+      _dl_exit (1);                                            \
+    }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+   is done.  */
+
+#define START()                                        \
+  __asm__ volatile ("unlk %%a6\n\t"            \
+                   "jmp %0@"                   \
+                   : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+   Not needed for m68k.  */
+#define do_rem(result, n, base)  ((result) = (n) % (base))
diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c
new file mode 100644 (file)
index 0000000..9b73efd
--- /dev/null
@@ -0,0 +1,358 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993, Eric Youngdale.
+   Copyright (C) 1995, Andreas Schwab.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* Adapted to ELF/68k by Andreas Schwab.  */
+
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char *_dl_reltypes[] =
+{
+  "R_68K_NONE",
+  "R_68K_32", "R_68K_16", "R_68K_8",
+  "R_68K_PC32", "R_68K_PC16", "R_68K_PC8",
+  "R_68K_GOT32", "R_68K_GOT16", "R_68K_GOT8",
+  "R_68K_GOT32O", "R_68K_GOT16O", "R_68K_GOT8O",
+  "R_68K_PLT32", "R_68K_PLT16", "R_68K_PLT8",
+  "R_68K_PLT32O", "R_68K_PLT16O", "R_68K_PLT8O",
+  "R_68K_COPY", "R_68K_GLOB_DAT", "R_68K_JMP_SLOT", "R_68K_RELATIVE",
+  "R_68K_NUM"
+};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+   References to symbols in sharable libraries can be resolved by either
+   an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include "../syscall.h"
+#include "../string.h"
+
+extern char *_dl_progname;
+
+unsigned int 
+_dl_linux_resolver (int dummy1, int dummy2,
+                   struct elf_resolve *tpnt, int reloc_entry)
+{
+  int reloc_type;
+  struct elf32_rela *this_reloc;
+  char *strtab;
+  struct elf32_sym *symtab;
+  char *rel_addr;
+  int symtab_index;
+  char *new_addr;
+  char **got_addr;
+  unsigned int instr_addr;
+
+  rel_addr = tpnt->loadaddr + tpnt->dynamic_info[DT_JMPREL];
+  this_reloc = (struct elf32_rela *) (rel_addr + reloc_entry);
+  reloc_type = ELF32_R_TYPE (this_reloc->r_info);
+  symtab_index = ELF32_R_SYM (this_reloc->r_info);
+
+  symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+                                + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+
+  if (reloc_type != R_68K_JMP_SLOT)
+    {
+      _dl_fdprintf (2, "%s: incorrect relocation type in jump relocations\n",
+                   _dl_progname);
+      _dl_exit (1);
+    }
+
+  /* Address of jump instruction to fix up.  */
+  instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr;
+  got_addr = (char **) instr_addr;
+
+#ifdef DEBUG
+  _dl_fdprintf (2, "Resolving symbol %s\n",
+               strtab + symtab[symtab_index].st_name);
+#endif
+
+  /* Get the address of the GOT entry.  */
+  new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
+                           tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+  if (!new_addr)
+    {
+      _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+                   _dl_progname, strtab + symtab[symtab_index].st_name);
+      _dl_exit (1);
+    }
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+  if ((unsigned int) got_addr < 0x40000000)
+    _dl_fdprintf (2, "Calling library function: %s\n",
+                 strtab + symtab[symtab_index].st_name);
+  else
+#endif
+    *got_addr = new_addr;
+  return (unsigned int) new_addr;
+}
+
+void
+_dl_parse_lazy_relocation_information (struct elf_resolve *tpnt, int rel_addr,
+                                      int rel_size, int type)
+{
+  int i;
+  char *strtab;
+  int reloc_type;
+  int symtab_index;
+  struct elf32_sym *symtab;
+  struct elf32_rela *rpnt;
+  unsigned int *reloc_addr;
+
+  /* Now parse the relocation information.  */
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof (struct elf32_rela);
+
+  symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+                                + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for (i = 0; i < rel_size; i++, rpnt++)
+    {
+      reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+      reloc_type = ELF32_R_TYPE (rpnt->r_info);
+      symtab_index = ELF32_R_SYM (rpnt->r_info);
+
+      /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+         Make sure we do not do them again.  */
+      if (tpnt->libtype == program_interpreter
+         && (!symtab_index
+             || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+       continue;
+
+      switch (reloc_type)
+       {
+       case R_68K_NONE:
+         break;
+       case R_68K_JMP_SLOT:
+         *reloc_addr += (unsigned int) tpnt->loadaddr;
+         break;
+       default:
+         _dl_fdprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+         _dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+         if (symtab_index)
+           _dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
+         _dl_fdprintf (2, "\n");
+         _dl_exit (1);
+       }
+    }
+}
+
+int 
+_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr,
+                                 int rel_size, int type)
+{
+  int i;
+  char *strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym *symtab;
+  struct elf32_rela *rpnt;
+  unsigned int *reloc_addr;
+  unsigned int symbol_addr;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof (struct elf32_rela);
+
+  symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+                                + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for (i = 0; i < rel_size; i++, rpnt++)
+    {
+      reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+      reloc_type = ELF32_R_TYPE (rpnt->r_info);
+      symtab_index = ELF32_R_SYM (rpnt->r_info);
+      symbol_addr = 0;
+
+      if (tpnt->libtype == program_interpreter
+         && (!symtab_index
+             || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+       continue;
+
+      if (symtab_index)
+       {
+         symbol_addr = (unsigned int)
+           _dl_find_hash (strtab + symtab[symtab_index].st_name,
+                          tpnt->symbol_scope, (int) reloc_addr,
+                          reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, 0);
+
+         /* We want to allow undefined references to weak symbols -
+            this might have been intentional.  We should not be
+            linking local symbols here, so all bases should be
+            covered.  */
+         if (!symbol_addr
+             && ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_GLOBAL)
+           {
+             _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+                           _dl_progname, strtab + symtab[symtab_index].st_name);
+             goof++;
+           }
+       }
+      switch (reloc_type)
+       {
+       case R_68K_NONE:
+         break;
+       case R_68K_8:
+         *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
+         break;
+       case R_68K_16:
+         *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
+         break;
+       case R_68K_32:
+         *reloc_addr = symbol_addr + rpnt->r_addend;
+         break;
+       case R_68K_PC8:
+         *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
+                                 - (unsigned int) reloc_addr);
+         break;
+       case R_68K_PC16:
+         *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
+                                  - (unsigned int) reloc_addr);
+         break;
+       case R_68K_PC32:
+         *reloc_addr = (symbol_addr + rpnt->r_addend
+                        - (unsigned int) reloc_addr);
+         break;
+       case R_68K_GLOB_DAT:
+       case R_68K_JMP_SLOT:
+         *reloc_addr = symbol_addr;
+         break;
+       case R_68K_RELATIVE:
+         *reloc_addr = ((unsigned int) tpnt->loadaddr
+                        /* Compatibility kludge.  */
+                        + (rpnt->r_addend ? : *reloc_addr));
+         break;
+       case R_68K_COPY:
+#if 0 /* Do this later.  */
+         _dl_fdprintf (2, "Doing copy");
+         if (symtab_index)
+           _dl_fdprintf (2, " for symbol %s",
+                         strtab + symtab[symtab_index].st_name);
+         _dl_fdprintf (2, "\n");
+         _dl_memcpy ((void *) symtab[symtab_index].st_value,
+                     (void *) symbol_addr,
+                     symtab[symtab_index].st_size);
+#endif
+         break;
+       default:
+         _dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+         _dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+         if (symtab_index)
+           _dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
+         _dl_fdprintf (2, "\n");
+         _dl_exit (1);
+       }
+
+    }
+  return goof;
+}
+
+/* This is done as a separate step, because there are cases where
+   information is first copied and later initialized.  This results in
+   the wrong information being copied.  Someone at Sun was complaining about
+   a bug in the handling of _COPY by SVr4, and this may in fact be what he
+   was talking about.  Sigh.  */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+   at all.  */
+
+int 
+_dl_parse_copy_information (struct dyn_elf *xpnt, int rel_addr,
+                           int rel_size, int type)
+{
+  int i;
+  char *strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym *symtab;
+  struct elf32_rela *rpnt;
+  unsigned int *reloc_addr;
+  unsigned int symbol_addr;
+  struct elf_resolve *tpnt;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  tpnt = xpnt->dyn;
+
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+  rel_size = rel_size / sizeof (struct elf32_rela);
+
+  symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+                                + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for (i = 0; i < rel_size; i++, rpnt++)
+    {
+      reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+      reloc_type = ELF32_R_TYPE (rpnt->r_info);
+      if (reloc_type != R_68K_COPY)
+       continue;
+      symtab_index = ELF32_R_SYM (rpnt->r_info);
+      symbol_addr = 0;
+      if (tpnt->libtype == program_interpreter
+         && (!symtab_index
+             || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+       continue;
+      if (symtab_index)
+       {
+         symbol_addr = (unsigned int)
+           _dl_find_hash (strtab + symtab[symtab_index].st_name,
+                          xpnt->next, (int) reloc_addr, NULL, 1);
+         if (!symbol_addr)
+           {
+             _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+                           _dl_progname, strtab + symtab[symtab_index].st_name);
+             goof++;
+           }
+       }
+      if (!goof)
+      _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
+                 symtab[symtab_index].st_size);
+    }
+  return goof;
+}
diff --git a/ldso/ldso/m68k/ld_sysdep.h b/ldso/ldso/m68k/ld_sysdep.h
new file mode 100644 (file)
index 0000000..24af47c
--- /dev/null
@@ -0,0 +1,87 @@
+
+/* Various assmbly language/system dependent hacks that are required
+   so that we can minimize the amount of platform specific code. */
+
+/* Define this if the system uses RELOCA.  */
+#define ELF_USES_RELOCA
+
+/* Get a pointer to the argv array.  On many platforms this can be
+   just the address if the first argument, on other platforms we need
+   to do something a little more subtle here.  */
+#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
+
+/* Get the address of the Global offset table.  This must be absolute,
+   not relative.  */
+#define GET_GOT(X)     __asm__ ("movel %%a5,%0" : "=g" (X))
+
+/* Initialization sequence for a GOT.  */
+#define INIT_GOT(GOT_BASE,MODULE)              \
+{                                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve;       \
+  GOT_BASE[1] = (int) (MODULE);                        \
+}
+
+/* Here is a macro to perform a relocation.  This is only used when
+   bootstrapping the dynamic loader.  RELP is the relocation that we
+   are performing, REL is the pointer to the address we are
+   relocating.  SYMBOL is the symbol involved in the relocation, and
+   LOAD is the load address. */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)          \
+  switch (ELF32_R_TYPE ((RELP)->r_info))                       \
+    {                                                          \
+    case R_68K_8:                                              \
+      *(char *) (REL) = (SYMBOL) + (RELP)->r_addend;           \
+      break;                                                   \
+    case R_68K_16:                                             \
+      *(short *) (REL) = (SYMBOL) + (RELP)->r_addend;          \
+      break;                                                   \
+    case R_68K_32:                                             \
+      *(REL) = (SYMBOL) + (RELP)->r_addend;                    \
+      break;                                                   \
+    case R_68K_PC8:                                            \
+      *(char *) (REL) = ((SYMBOL) + (RELP)->r_addend           \
+                        - (unsigned int) (REL));               \
+      break;                                                   \
+    case R_68K_PC16:                                           \
+      *(short *) (REL) = ((SYMBOL) + (RELP)->r_addend          \
+                         - (unsigned int) (REL));              \
+      break;                                                   \
+    case R_68K_PC32:                                           \
+      *(REL) = ((SYMBOL) + (RELP)->r_addend                    \
+               - (unsigned int) (REL));                        \
+      break;                                                   \
+    case R_68K_GLOB_DAT:                                       \
+    case R_68K_JMP_SLOT:                                       \
+      *(REL) = (SYMBOL);                                       \
+      break;                                                   \
+    case R_68K_RELATIVE:               /* Compatibility kludge */ \
+      *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+      break;                                                   \
+    default:                                                   \
+      _dl_exit (1);                                            \
+    }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+   is done.  */
+
+#define START()                                        \
+  __asm__ volatile ("unlk %%a6\n\t"            \
+                   "jmp %0@"                   \
+                   : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+   Not needed for m68k.  */
+#define do_rem(result, n, base)  ((result) = (n) % (base))
diff --git a/ldso/ldso/m68k/resolve.S b/ldso/ldso/m68k/resolve.S
new file mode 100644 (file)
index 0000000..9b1a24c
--- /dev/null
@@ -0,0 +1,29 @@
+#if 0
+#include <sysdep.h>
+#endif
+/*
+ * These are various helper routines that are needed to run an ELF image.
+ */
+
+#ifdef NO_UNDERSCORE
+#define __dl_linux_resolve _dl_linux_resolve
+#define __dl_linux_resolver _dl_linux_resolver
+#endif
+
+.text
+.even
+
+.globl __dl_linux_resolve
+       .type   __dl_linux_resolve,@function
+__dl_linux_resolve:
+       moveml  %a0/%a1,%sp@-
+#ifdef __PIC__
+       bsrl    __dl_linux_resolver@PLTPC
+#else
+       jbsr    __dl_linux_resolver
+#endif
+       moveml  %sp@+,%a0/%a1
+       addql   #8,%sp
+       jmp     @(%d0)
+.LFE2:
+       .size __dl_linux_resolve,.LFE2-__dl_linux_resolve
diff --git a/ldso/ldso/m68k/sysdep.h b/ldso/ldso/m68k/sysdep.h
new file mode 100644 (file)
index 0000000..24af47c
--- /dev/null
@@ -0,0 +1,87 @@
+
+/* Various assmbly language/system dependent hacks that are required
+   so that we can minimize the amount of platform specific code. */
+
+/* Define this if the system uses RELOCA.  */
+#define ELF_USES_RELOCA
+
+/* Get a pointer to the argv array.  On many platforms this can be
+   just the address if the first argument, on other platforms we need
+   to do something a little more subtle here.  */
+#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
+
+/* Get the address of the Global offset table.  This must be absolute,
+   not relative.  */
+#define GET_GOT(X)     __asm__ ("movel %%a5,%0" : "=g" (X))
+
+/* Initialization sequence for a GOT.  */
+#define INIT_GOT(GOT_BASE,MODULE)              \
+{                                              \
+  GOT_BASE[2] = (int) _dl_linux_resolve;       \
+  GOT_BASE[1] = (int) (MODULE);                        \
+}
+
+/* Here is a macro to perform a relocation.  This is only used when
+   bootstrapping the dynamic loader.  RELP is the relocation that we
+   are performing, REL is the pointer to the address we are
+   relocating.  SYMBOL is the symbol involved in the relocation, and
+   LOAD is the load address. */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)          \
+  switch (ELF32_R_TYPE ((RELP)->r_info))                       \
+    {                                                          \
+    case R_68K_8:                                              \
+      *(char *) (REL) = (SYMBOL) + (RELP)->r_addend;           \
+      break;                                                   \
+    case R_68K_16:                                             \
+      *(short *) (REL) = (SYMBOL) + (RELP)->r_addend;          \
+      break;                                                   \
+    case R_68K_32:                                             \
+      *(REL) = (SYMBOL) + (RELP)->r_addend;                    \
+      break;                                                   \
+    case R_68K_PC8:                                            \
+      *(char *) (REL) = ((SYMBOL) + (RELP)->r_addend           \
+                        - (unsigned int) (REL));               \
+      break;                                                   \
+    case R_68K_PC16:                                           \
+      *(short *) (REL) = ((SYMBOL) + (RELP)->r_addend          \
+                         - (unsigned int) (REL));              \
+      break;                                                   \
+    case R_68K_PC32:                                           \
+      *(REL) = ((SYMBOL) + (RELP)->r_addend                    \
+               - (unsigned int) (REL));                        \
+      break;                                                   \
+    case R_68K_GLOB_DAT:                                       \
+    case R_68K_JMP_SLOT:                                       \
+      *(REL) = (SYMBOL);                                       \
+      break;                                                   \
+    case R_68K_RELATIVE:               /* Compatibility kludge */ \
+      *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+      break;                                                   \
+    default:                                                   \
+      _dl_exit (1);                                            \
+    }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+   is done.  */
+
+#define START()                                        \
+  __asm__ volatile ("unlk %%a6\n\t"            \
+                   "jmp %0@"                   \
+                   : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+   Not needed for m68k.  */
+#define do_rem(result, n, base)  ((result) = (n) % (base))
diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c
new file mode 100644 (file)
index 0000000..9d1cd0f
--- /dev/null
@@ -0,0 +1,588 @@
+/* Load an ELF sharable library into memory.
+
+   Copyright (C) 1993-1996, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+
+/* This file contains the helper routines to load an ELF sharable
+   library into memory and add the symbol table info to the chain. */
+
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "string.h"
+/*#include <stdlib.h>*/
+#include <linux/mman.h>
+#include <linux/stat.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+#ifdef USE_CACHE
+#include "../config.h"
+#endif
+
+extern char *_dl_progname;
+
+#ifdef USE_CACHE
+
+static caddr_t _dl_cache_addr = NULL;
+static size_t _dl_cache_size = 0;
+
+int _dl_map_cache(void)
+{
+  int fd;
+  struct kernel_stat st;
+  header_t *header;
+  libentry_t *libent;
+  int i, strtabsize;
+
+  if (_dl_cache_addr == (caddr_t)-1)
+    return -1;
+  else if (_dl_cache_addr != NULL)
+    return 0;
+
+  if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
+  {
+    _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
+    _dl_cache_addr = (caddr_t)-1; /* so we won't try again */
+    return -1;
+  }
+
+  _dl_cache_size = st.st_size;
+  _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
+                                    MAP_SHARED, fd, 0);
+  _dl_close (fd);
+  if (_dl_cache_addr == (caddr_t)-1)
+  {
+    _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
+    return -1;
+  }
+
+  header = (header_t *)_dl_cache_addr;
+
+  if (_dl_cache_size < sizeof (header_t) ||
+      _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
+      _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
+      _dl_cache_size < 
+        (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
+      _dl_cache_addr[_dl_cache_size-1] != '\0')
+  {
+    _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+    goto fail;
+  }
+
+  strtabsize = _dl_cache_size - sizeof (header_t) - 
+    header->nlibs * sizeof (libentry_t);
+  libent = (libentry_t *)&header[1];
+
+  for (i = 0; i < header->nlibs; i++)
+  {
+    if (libent[i].sooffset >= strtabsize ||
+       libent[i].liboffset >= strtabsize)
+    {
+      _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+      goto fail;
+    }
+  }
+
+  return 0;
+
+fail:
+  _dl_munmap(_dl_cache_addr, _dl_cache_size);
+  _dl_cache_addr = (caddr_t)-1;
+  return -1;
+}
+
+int _dl_unmap_cache(void)
+{
+  if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
+    return -1;
+
+#if 1
+  _dl_munmap (_dl_cache_addr, _dl_cache_size);
+  _dl_cache_addr = NULL;
+#endif
+
+  return 0;
+}
+
+#endif
+
+/*
+ * Used to return error codes back to dlopen et. al.
+ */
+
+unsigned int _dl_error_number;
+unsigned int _dl_internal_error_number;
+
+struct elf_resolve * _dl_load_shared_library(int secure, 
+       struct elf_resolve * tpnt, char * full_libname) {
+  char * pnt, *pnt1, *pnt2;
+  struct elf_resolve *tpnt1 = NULL;
+  char mylibname[2050];
+  char * libname;
+
+  _dl_internal_error_number = 0;
+
+  /* quick hack to ensure mylibname buffer doesn't overflow.  don't 
+     allow full_libname or any directory to be longer than 1024. */
+  if (_dl_strlen(full_libname) > 1024)
+    goto goof;
+
+  pnt = libname = full_libname;
+  while (*pnt) {
+    if(*pnt == '/') libname = pnt+1;
+    pnt++;
+  }
+
+ /* If the filename has any '/', try it straight and leave it at that.
+     For IBCS2 compatibility under linux, we substitute the string 
+     /usr/i486-sysv4/lib for /usr/lib in library names. */
+
+  if (libname != full_libname) {
+    tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
+    if (tpnt1)
+      return tpnt1;
+    goto goof;
+  }
+
+  /*
+   * The ABI specifies that RPATH is searched before LD_*_PATH or
+   * the default path of /usr/lib.
+   * Check in rpath directories 
+   */
+  for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+    if (tpnt->libtype == elf_executable) {
+      pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
+      if(pnt1) {
+       pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
+       while(*pnt1){
+         pnt2 = mylibname;
+         while(*pnt1 && *pnt1 != ':') {
+           if (pnt2 - mylibname < 1024)
+             *pnt2++ = *pnt1++;
+           else
+             pnt1++;
+         }
+         if (pnt2 - mylibname >= 1024)
+           break;
+         if(pnt2[-1] != '/') *pnt2++ = '/';
+         pnt = libname;
+         while(*pnt) *pnt2++  = *pnt++;
+         *pnt2++ = 0;
+         tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+         if(tpnt1) return tpnt1;
+         if(*pnt1 == ':') pnt1++;
+       }
+      }
+    }
+  }
+  
+
+  /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
+  pnt1 = _dl_library_path;
+  if (pnt1 && *pnt1) {
+    while (*pnt1) {
+      pnt2 = mylibname;
+      while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
+       if (pnt2 - mylibname < 1024)
+         *pnt2++ = *pnt1++;
+       else
+         pnt1++;
+      }
+      if (pnt2 - mylibname >= 1024)
+       break;
+      if(pnt2[-1] != '/') *pnt2++ = '/';
+      pnt = libname;
+      while(*pnt) *pnt2++  = *pnt++;
+      *pnt2++ = 0;
+      tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+      if(tpnt1) return tpnt1;
+      if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
+    }
+  }
+
+
+  /*
+   * Where should the cache be searched?  There is no such concept in the
+   * ABI, so we have some flexibility here.  For now, search it before
+   * the default path of /usr/lib.
+   */
+#ifdef USE_CACHE
+  if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
+  {
+    int i;
+    header_t *header = (header_t *)_dl_cache_addr;
+    libentry_t *libent = (libentry_t *)&header[1];
+    char *strs = (char *)&libent[header->nlibs];
+
+    for (i = 0; i < header->nlibs; i++)
+    {
+      if ((libent[i].flags == LIB_ELF || 
+          libent[i].flags == LIB_ELF_LIBC5) &&
+         _dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
+         (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
+       return tpnt1;
+    }
+  }
+#endif
+
+
+#ifdef UCLIBC_DEVEL
+
+  /* Check in /usr/<arch>-linux-uclibc/lib */
+  pnt1 = UCLIBC_INSTALL_DIR"/lib";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+  
+#else /* UCLIBC_DEVEL */
+
+  /* Check in /usr/lib */
+  pnt1 = "/usr/lib/";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+  
+  /* Check in /lib */
+  /* try "/lib/". */
+  pnt1 = "/lib/";
+  pnt = mylibname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  pnt1 = libname;
+  while(*pnt1) *pnt++ = *pnt1++;
+  *pnt++ = 0;
+  tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+  if (tpnt1) return tpnt1;
+#endif /* UCLIBC_DEVEL */
+
+goof:
+  /* Well, we shot our wad on that one.  All we can do now is punt */
+  if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
+       else _dl_error_number = DL_ERROR_NOFILE;
+  return NULL;
+}
+
+/*
+ * Read one ELF library into memory, mmap it into the correct locations and
+ * add the symbol info to the symbol chain.  Perform any relocations that
+ * are required.
+ */
+
+//extern _elf_rtbndr(void);
+
+struct elf_resolve * _dl_load_elf_shared_library(int secure, 
+        char * libname, int flag) {
+  struct elfhdr * epnt;
+  unsigned int dynamic_addr = 0;
+  unsigned int dynamic_size = 0;
+  struct dynamic * dpnt;
+  struct elf_resolve * tpnt;
+  struct elf_phdr * ppnt;
+  int piclib;
+  char * status;
+  int flags;
+  char header[4096];
+  int dynamic_info[24];
+  int * lpnt;
+  unsigned int libaddr;
+  unsigned int minvma=0xffffffff, maxvma=0;
+  
+  int i;
+  int infile;
+
+  /* If this file is already loaded, skip this step */
+  tpnt = _dl_check_hashed_files(libname);
+  if(tpnt) return tpnt;
+
+  /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
+     we don't load the library if it isn't setuid. */
+
+  if (secure) {
+    struct kernel_stat st;
+    if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
+      return NULL;
+  }
+
+  libaddr = 0;
+  infile = _dl_open(libname, O_RDONLY);
+  if(infile < 0)
+  {
+#if 0
+    /*
+     * NO!  When we open shared libraries we may search several paths.
+     * it is inappropriate to generate an error here.
+     */
+    _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
+#endif
+    _dl_internal_error_number = DL_ERROR_NOFILE;
+    return NULL;
+  }
+  _dl_read(infile, header, sizeof(header));
+  epnt = (struct elfhdr *) header;
+  if (epnt->e_ident[0] != 0x7f ||
+      epnt->e_ident[1] != 'E' ||
+      epnt->e_ident[2] != 'L' ||
+      epnt->e_ident[3] != 'F') {
+    _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
+    _dl_internal_error_number = DL_ERROR_NOTELF;
+    _dl_close(infile);
+    return NULL;
+  };
+  
+  if((epnt->e_type != ET_DYN) || 
+     (epnt->e_machine != MAGIC1 
+#ifdef MAGIC2
+      && epnt->e_machine != MAGIC2
+#endif
+      )){
+    _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
+    _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
+                _dl_progname, libname);
+    _dl_close(infile);
+    return NULL;
+  };
+
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+  piclib = 1;
+  for(i=0;i < epnt->e_phnum; i++){
+
+    if(ppnt->p_type == PT_DYNAMIC) {
+      if (dynamic_addr)
+       _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
+                    _dl_progname, libname);
+      dynamic_addr = ppnt->p_vaddr;
+      dynamic_size = ppnt->p_filesz;
+    };
+
+    if(ppnt->p_type == PT_LOAD) {
+       /* See if this is a PIC library. */
+       if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+           piclib = 0;
+           minvma=ppnt->p_vaddr;
+       }
+       if(piclib && ppnt->p_vaddr < minvma) {
+           minvma = ppnt->p_vaddr;
+       }
+       if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
+           maxvma = ppnt->p_vaddr + ppnt->p_memsz;
+       }
+     }
+    ppnt++;
+  };
+
+  maxvma=(maxvma+0xfffU)&~0xfffU;
+  minvma=minvma&~0xffffU;
+  
+  flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
+  if(!piclib) flags |= MAP_FIXED;
+  
+  status = (char *) _dl_mmap((char *) (piclib?0:minvma),
+                         maxvma-minvma, 
+                         PROT_NONE, 
+                         flags | MAP_ANONYMOUS, -1,
+                         0);
+  if(_dl_mmap_check_error(status)) {
+    _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+    _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+    _dl_close(infile);
+     return NULL;
+  };
+  libaddr=(unsigned int)status;
+  flags|=MAP_FIXED;
+
+  /* Get the memory to store the library */
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+  
+  for(i=0;i < epnt->e_phnum; i++){
+    if(ppnt->p_type == PT_LOAD) {
+
+      /* See if this is a PIC library. */
+      if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+       piclib = 0;
+       /* flags |= MAP_FIXED; */
+      }
+
+
+      
+      if(ppnt->p_flags & PF_W) {
+       unsigned int map_size;
+       char * cpnt;
+       
+       status = (char *) _dl_mmap((char *) ((piclib?libaddr:0)  +
+                                            (ppnt->p_vaddr & 0xfffff000)),
+                         (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, 
+                         LXFLAGS(ppnt->p_flags), 
+                         flags, infile,
+                         ppnt->p_offset & 0x7ffff000);
+       
+       if(_dl_mmap_check_error(status)) {
+           _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+           _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+           _dl_munmap((char *)libaddr, maxvma-minvma);
+           _dl_close(infile);
+           return NULL;
+       };
+       
+       /* Pad the last page with zeroes. */
+       cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
+       while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
+
+/* I am not quite sure if this is completely correct to do or not, but
+   the basic way that we handle bss segments is that we mmap /dev/zero if
+   there are any pages left over that are not mapped as part of the file */
+
+       map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
+       if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
+         status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0), 
+                           ppnt->p_vaddr + ppnt->p_memsz - map_size,
+                           LXFLAGS(ppnt->p_flags),
+                           flags | MAP_ANONYMOUS, -1, 0);
+      } else
+       status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + 
+                                  (piclib?libaddr:0), 
+                         (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz, 
+                         LXFLAGS(ppnt->p_flags), 
+                         flags, infile, 
+                         ppnt->p_offset & 0x7ffff000);
+      if(_dl_mmap_check_error(status)) {
+       _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+       _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+       _dl_munmap((char *)libaddr, maxvma-minvma);
+       _dl_close(infile);
+       return NULL;
+      };
+
+      /* if(libaddr == 0 && piclib) {
+       libaddr = (unsigned int) status;
+       flags |= MAP_FIXED;
+      }; */
+    };
+    ppnt++;
+  };
+  _dl_close(infile);
+  
+  /* For a non-PIC library, the addresses are all absolute */
+  if(piclib) {
+    dynamic_addr += (unsigned int) libaddr;
+  }
+
+ /* 
+  * OK, the ELF library is now loaded into VM in the correct locations
+  * The next step is to go through and do the dynamic linking (if needed).
+  */
+  
+  /* Start by scanning the dynamic section to get all of the pointers */
+  
+  if(!dynamic_addr) {
+    _dl_internal_error_number = DL_ERROR_NODYNAMIC;
+    _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
+    return NULL;
+  }
+
+  dpnt = (struct dynamic *) dynamic_addr;
+
+  dynamic_size = dynamic_size / sizeof(struct dynamic);
+  _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
+  for(i=0; i< dynamic_size; i++){
+    if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
+    dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+    if(dpnt->d_tag == DT_TEXTREL ||
+       SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
+    dpnt++;
+  };
+
+  /* If the TEXTREL is set, this means that we need to make the pages
+     writable before we perform relocations.  Do this now. They get set back
+     again later. */
+
+  if (dynamic_info[DT_TEXTREL]) {
+  ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+  for(i=0;i < epnt->e_phnum; i++, ppnt++){
+    if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+      _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
+                  (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+                  PROT_READ | PROT_WRITE | PROT_EXEC);
+  }
+  }
+
+
+  tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr, 
+                             dynamic_size);
+
+  tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
+  tpnt->n_phent = epnt->e_phnum;
+
+  /*
+   * OK, the next thing we need to do is to insert the dynamic linker into
+   * the proper entry in the GOT so that the PLT symbols can be properly
+   * resolved. 
+   */
+  
+  lpnt = (int *) dynamic_info[DT_PLTGOT];
+  
+  if(lpnt) {
+    lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
+    INIT_GOT(lpnt, tpnt);
+  };
+  
+  return tpnt;
+}
+
+/* Ugly, ugly.  Some versions of the SVr4 linker fail to generate COPY
+   relocations for global variables that are present both in the image and
+   the shared library.  Go through and do it manually.  If the images
+   are guaranteed to be generated by a trustworthy linker, then this
+   step can be skipped. */
+
+int _dl_copy_fixups(struct dyn_elf * rpnt)
+{
+  int goof = 0;
+  struct elf_resolve * tpnt;
+
+  if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
+  else return 0;
+
+  tpnt = rpnt->dyn;
+       
+  if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
+  tpnt->init_flag |= COPY_RELOCS_DONE;
+  
+#ifdef ELF_USES_RELOCA
+  goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
+                                          tpnt->dynamic_info[DT_RELASZ], 0);
+
+#else
+  goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
+                                          tpnt->dynamic_info[DT_RELSZ], 0);
+
+#endif
+  return goof;
+}
+
diff --git a/ldso/ldso/sparc/DEFS.h b/ldso/ldso/sparc/DEFS.h
new file mode 100644 (file)
index 0000000..4b9abcc
--- /dev/null
@@ -0,0 +1,5 @@
+#define        FUNC(name)      \
+       .global name;   \
+       .type name,@function;     \
+       .align 4;       \
+       name:
diff --git a/ldso/ldso/sparc/dl-sysdep.h b/ldso/ldso/sparc/dl-sysdep.h
new file mode 100644 (file)
index 0000000..1d4c035
--- /dev/null
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.  We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT.  For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots.  The PLT should
+ * look like:
+ *
+ *             save %sp, -64, %sp
+ *             call _dl_linux_resolve
+ *             nop
+ *             .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+   GOT_BASE[0] = 0x9de3bfc0;  /* save %sp, -64, %sp */ \
+   GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+   GOT_BASE[2] = 0x01000000; /* nop */                         \
+   GOT_BASE[3] = (int) MODULE;                                 \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)) {          \
+       case R_SPARC_32:                                \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_GLOB_DAT:                          \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_JMP_SLOT:                          \
+         REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff);    \
+         REL[2] = 0x81c06000 | (SYMBOL & 0x3ff);       \
+         break;                                        \
+       case R_SPARC_NONE:                              \
+         break;                                        \
+        case R_SPARC_WDISP30:                          \
+          break;                                        \
+       case R_SPARC_RELATIVE:                          \
+         *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+         break;                                        \
+       default:                                        \
+         _dl_exit(1);                                  \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START()                \
+       __asm__ volatile ( \
+                          "add %%g0,%%g0,%%g1\n\t" \
+                          "jmpl %0, %%o7\n\t"  \
+                          "restore %%g0,%%g0,%%g0\n\t" \
+                       : /*"=r" (status) */ :  \
+                         "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+                                       unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv.  This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+       "sdiv %2,%3,%%l6\n\t" \
+        "smul %%l6,%3,%%l6\n\t" \
+        "sub  %2,%%l6,%0\n\t" \
+        :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name.  Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c
new file mode 100644 (file)
index 0000000..6f0d9f8
--- /dev/null
@@ -0,0 +1,355 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1995, Eric Youngdale.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char * _dl_reltypes[] = { "R_SPARC_NONE", "R_SPARC_8",
+  "R_SPARC_16", "R_SPARC_32", "R_SPARC_DISP8", "R_SPARC_DISP16",
+  "R_SPARC_DISP32", "R_SPARC_WDISP30", "R_SPARC_WDISP22",
+  "R_SPARC_HI22", "R_SPARC_22", "R_SPARC_13", "R_SPARC_LO10",
+  "R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", "R_SPARC_PC10",
+  "R_SPARC_PC22", "R_SPARC_WPLT30", "R_SPARC_COPY",
+  "R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", "R_SPARC_RELATIVE",
+  "R_SPARC_UA32"};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+References to symbols in sharable libraries can be resolved by either
+an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include "../syscall.h"
+#include "../string.h"
+
+#define SVR4_COMPATIBILITY
+
+extern char *_dl_progname;
+
+extern _dl_linux_resolve(void);
+
+unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
+{
+  int reloc_type;
+  struct elf32_rela * this_reloc;
+  char * strtab;
+  struct elf32_sym * symtab; 
+  struct elf32_rela * rel_addr;
+  struct elf_resolve * tpnt;
+  int symtab_index;
+  char * new_addr;
+  char ** got_addr;
+  unsigned int instr_addr;
+  tpnt = (struct elf_resolve *) plt[2];
+
+  rel_addr = (struct elf32_rela *) (tpnt->dynamic_info[DT_JMPREL] + 
+                                  tpnt->loadaddr);
+
+  /*
+   * Generate the correct relocation index into the .rela.plt section.
+   */
+  reloc_entry = (reloc_entry >> 12) - 0xc;
+
+  this_reloc = (struct elf32_rela *) ((char *) rel_addr + reloc_entry);
+
+  reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+  symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  _dl_fdprintf(2, "tpnt = %x\n", tpnt);
+  _dl_fdprintf(2, "reloc = %x\n", this_reloc);
+  _dl_fdprintf(2, "symtab = %x\n", symtab);
+  _dl_fdprintf(2, "strtab = %x\n", strtab);
+
+
+  if (reloc_type != R_SPARC_JMP_SLOT) {
+    _dl_fdprintf(2, "%s: incorrect relocation type in jump relocations (%d)\n",
+                 _dl_progname, reloc_type);
+    _dl_exit(30);
+  };
+
+  /* Address of jump instruction to fix up */
+  instr_addr  = ((int)this_reloc->r_offset  + (int)tpnt->loadaddr);
+  got_addr = (char **) instr_addr;
+
+  _dl_fdprintf(2, "symtab_index %d\n", symtab_index);
+
+#ifdef DEBUG
+  _dl_fdprintf(2, "Resolving symbol %s\n",
+       strtab + symtab[symtab_index].st_name);
+#endif
+
+  /* Get the address of the GOT entry */
+  new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, 
+                       tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+  if(!new_addr) {
+    _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+              _dl_progname, strtab + symtab[symtab_index].st_name);
+    _dl_exit(31);
+  };
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+  if((unsigned int) got_addr < 0x40000000) {
+    _dl_fdprintf(2, "Calling library function: %s\n",
+              strtab + symtab[symtab_index].st_name);
+  } else {
+    got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
+    got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
+  }
+#else
+  got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
+  got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
+#endif
+  _dl_fdprintf(2, "Address = %x\n",new_addr);
+    _dl_exit(32);
+
+  return (unsigned int) new_addr;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type){
+  int i;
+  char * strtab;
+  int reloc_type;
+  int symtab_index;
+  struct elf32_sym * symtab; 
+  struct elf32_rela * rpnt;
+  unsigned int * reloc_addr;
+
+  /* Now parse the relocation information */
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i += sizeof(struct elf32_rela), rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+    /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+       Make sure we do not do them again */
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+    if(symtab_index && tpnt->libtype == program_interpreter &&
+       _dl_symbol(strtab + symtab[symtab_index].st_name))
+      continue;
+
+    switch(reloc_type){
+    case R_SPARC_NONE:
+      break;
+    case R_SPARC_JMP_SLOT:
+      break;
+    default:
+      _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+      _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+      if(symtab_index) _dl_fdprintf(2, "'%s'\n",
+                                 strtab + symtab[symtab_index].st_name);
+      _dl_exit(33);
+    };
+  };
+}
+
+int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+       int rel_size, int type){
+  int i;
+  char * strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym * symtab; 
+  struct elf32_rela * rpnt;
+  unsigned int * reloc_addr;
+  unsigned int symbol_addr;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+    symbol_addr = 0;
+
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+
+    if(symtab_index) {
+
+      if(tpnt->libtype == program_interpreter && 
+        _dl_symbol(strtab + symtab[symtab_index].st_name))
+       continue;
+
+      symbol_addr = (unsigned int) 
+       _dl_find_hash(strtab + symtab[symtab_index].st_name,
+                             tpnt->symbol_scope, (int) reloc_addr, 
+                     (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), 0);
+
+      if(!symbol_addr &&
+        ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
+       _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+                    _dl_progname, strtab + symtab[symtab_index].st_name);
+       goof++;
+      };
+    };
+    switch(reloc_type){
+    case R_SPARC_NONE:
+       break;
+    case R_SPARC_32:
+      *reloc_addr = symbol_addr + rpnt->r_addend;
+      break;
+    case R_SPARC_DISP32:
+      *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
+      break;
+    case R_SPARC_GLOB_DAT:
+      *reloc_addr = symbol_addr + rpnt->r_addend;
+      break;
+    case R_SPARC_JMP_SLOT:
+      reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
+      reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
+      break;
+    case R_SPARC_RELATIVE:
+      *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
+      break;
+    case R_SPARC_HI22:
+      if (!symbol_addr)
+        symbol_addr = tpnt->loadaddr + rpnt->r_addend;
+      else
+       symbol_addr += rpnt->r_addend;
+      *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
+      break;
+    case R_SPARC_LO10:
+      if (!symbol_addr)
+        symbol_addr = tpnt->loadaddr + rpnt->r_addend;
+      else
+       symbol_addr += rpnt->r_addend;
+      *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
+      break;
+    case R_SPARC_WDISP30:
+      *reloc_addr = (*reloc_addr & 0xc0000000)|
+       ((symbol_addr - (unsigned int) reloc_addr) >> 2);
+      break;
+    case R_SPARC_COPY:
+#if 0 /* This one is done later */
+      _dl_fdprintf(2, "Doing copy for symbol ");
+      if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
+      _dl_fdprintf(2, "\n");
+      _dl_memcpy((void *) symtab[symtab_index].st_value,
+                (void *) symbol_addr, 
+                symtab[symtab_index].st_size);
+#endif
+      break;
+    default:
+      _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+      _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+      if (symtab_index)
+       _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
+      _dl_exit(34);
+    };
+
+  };
+  return goof;
+}
+
+
+/* This is done as a separate step, because there are cases where
+   information is first copied and later initialized.  This results in
+   the wrong information being copied.  Someone at Sun was complaining about
+   a bug in the handling of _COPY by SVr4, and this may in fact be what he
+   was talking about.  Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+   at all */
+
+int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
+       int rel_size, int type)
+{
+  int i;
+  char * strtab;
+  int reloc_type;
+  int goof = 0;
+  struct elf32_sym * symtab; 
+  struct elf32_rela * rpnt;
+  unsigned int * reloc_addr;
+  unsigned int symbol_addr;
+  struct elf_resolve *tpnt;
+  int symtab_index;
+  /* Now parse the relocation information */
+
+  tpnt = xpnt->dyn;
+  
+  rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+  symtab =  (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+  for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
+    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+    reloc_type = ELF32_R_TYPE(rpnt->r_info);
+    if(reloc_type != R_SPARC_COPY) continue;
+    symtab_index = ELF32_R_SYM(rpnt->r_info);
+    symbol_addr = 0;
+    if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+    if(symtab_index) {
+
+      if(tpnt->libtype == program_interpreter && 
+        _dl_symbol(strtab + symtab[symtab_index].st_name))
+       continue;
+
+      symbol_addr = (unsigned int) 
+       _dl_find_hash(strtab + symtab[symtab_index].st_name,
+                             xpnt->next, (int) reloc_addr, NULL, 1);
+      if(!symbol_addr) {
+       _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+                  _dl_progname, strtab + symtab[symtab_index].st_name);
+       goof++;
+      };
+    };
+    if (!goof)
+      _dl_memcpy((char *) symtab[symtab_index].st_value, 
+                 (char *) symbol_addr, 
+                 symtab[symtab_index].st_size);
+  };
+  return goof;
+}
+
+
diff --git a/ldso/ldso/sparc/ld_sysdep.h b/ldso/ldso/sparc/ld_sysdep.h
new file mode 100644 (file)
index 0000000..1d4c035
--- /dev/null
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.  We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT.  For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots.  The PLT should
+ * look like:
+ *
+ *             save %sp, -64, %sp
+ *             call _dl_linux_resolve
+ *             nop
+ *             .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+   GOT_BASE[0] = 0x9de3bfc0;  /* save %sp, -64, %sp */ \
+   GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+   GOT_BASE[2] = 0x01000000; /* nop */                         \
+   GOT_BASE[3] = (int) MODULE;                                 \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)) {          \
+       case R_SPARC_32:                                \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_GLOB_DAT:                          \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_JMP_SLOT:                          \
+         REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff);    \
+         REL[2] = 0x81c06000 | (SYMBOL & 0x3ff);       \
+         break;                                        \
+       case R_SPARC_NONE:                              \
+         break;                                        \
+        case R_SPARC_WDISP30:                          \
+          break;                                        \
+       case R_SPARC_RELATIVE:                          \
+         *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+         break;                                        \
+       default:                                        \
+         _dl_exit(1);                                  \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START()                \
+       __asm__ volatile ( \
+                          "add %%g0,%%g0,%%g1\n\t" \
+                          "jmpl %0, %%o7\n\t"  \
+                          "restore %%g0,%%g0,%%g0\n\t" \
+                       : /*"=r" (status) */ :  \
+                         "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+                                       unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv.  This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+       "sdiv %2,%3,%%l6\n\t" \
+        "smul %%l6,%3,%%l6\n\t" \
+        "sub  %2,%%l6,%0\n\t" \
+        :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name.  Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/resolve.S b/ldso/ldso/sparc/resolve.S
new file mode 100644 (file)
index 0000000..ea985b5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * These are various helper routines that are needed to run an ELF image.
+ */
+#define COMPILE_ASM
+#include "sysdep.h"
+
+.text
+       .align 16
+
+.globl _dl_linux_resolve
+_dl_linux_resolve:
+       /*
+        * Call the resolver - pass the address of the PLT so that we can
+        * figure out which module we are in.
+        */
+       mov %o7,%o1
+       call  _dl_linux_resolver
+       mov %g1,%o0
+
+       jmpl %o0,%o7
+       restore
+.LFE2:
+
+       .type   _dl_linux_resolve,#function
+       .size _dl_linux_resolve,.LFE2-_dl_linux_resolve
diff --git a/ldso/ldso/sparc/sdiv.S b/ldso/ldso/sparc/sdiv.S
new file mode 100644 (file)
index 0000000..5e52e19
--- /dev/null
@@ -0,0 +1,369 @@
+   /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ *  .div       name of function to generate
+ *  div                div=div => %o0 / %o1; div=rem => %o0 % %o1
+ *  true               true=true => signed; true=false => unsigned
+ *
+ * Algorithm parameters:
+ *  N          how many bits per iteration we try to get (4)
+ *  WORDSIZE   total number of bits (32)
+ *
+ * Derived constants:
+ *  TOPBITS    number of bits in the top decade of a number
+ *
+ * Important variables:
+ *  Q          the partial quotient under development (initially 0)
+ *  R          the remainder so far, initially the dividend
+ *  ITER       number of main division loop iterations required;
+ *             equal to ceil(log2(quotient) / N).  Note that this
+ *             is the log base (2^N) of the quotient.
+ *  V          the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ *  Current estimate for non-large dividend is
+ *     ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ *  A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ *  different path, as the upper bits of the quotient must be developed
+ *  one bit at a time.
+ */
+
+
+
+#include "DEFS.h"
+#ifndef __linux__
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#else
+#include <asm/traps.h>
+#endif
+
+FUNC(_dl_div)
+       ! compute sign of result; if neither is negative, no problem
+       orcc    %o1, %o0, %g0   ! either negative?
+       bge     2f                      ! no, go do the divide
+       xor     %o1, %o0, %g6   ! compute sign in any case
+       tst     %o1
+       bge     1f
+       tst     %o0
+       ! %o1 is definitely negative; %o0 might also be negative
+       bge     2f                      ! if %o0 not negative...
+       sub     %g0, %o1, %o1   ! in any case, make %o1 nonneg
+1:     ! %o0 is negative, %o1 is nonnegative
+       sub     %g0, %o0, %o0   ! make %o0 nonnegative
+2:
+
+       ! Ready to divide.  Compute size of quotient; scale comparand.
+       orcc    %o1, %g0, %o5
+       bne     1f
+       mov     %o0, %o3
+
+               ! Divide by zero trap.  If it returns, return 0 (about as
+               ! wrong as possible, but that is what SunOS does...).
+               ta      ST_DIV0
+               retl
+               clr     %o0
+
+1:
+       cmp     %o3, %o5                        ! if %o1 exceeds %o0, done
+       blu     Lgot_result             ! (and algorithm fails otherwise)
+       clr     %o2
+       sethi   %hi(1 << (32 - 4 - 1)), %g1
+       cmp     %o3, %g1
+       blu     Lnot_really_big
+       clr     %o4
+
+       ! Here the dividend is >= 2**(31-N) or so.  We must be careful here,
+       ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+       ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+       ! Compute ITER in an unorthodox manner: know we need to shift V into
+       ! the top decade: so do not even bother to compare to R.
+       1:
+               cmp     %o5, %g1
+               bgeu    3f
+               mov     1, %g7
+               sll     %o5, 4, %o5
+               b       1b
+               add     %o4, 1, %o4
+
+       ! Now compute %g7.
+       2:      addcc   %o5, %o5, %o5
+               bcc     Lnot_too_big
+               add     %g7, 1, %g7
+
+               ! We get here if the %o1 overflowed while shifting.
+               ! This means that %o3 has the high-order bit set.
+               ! Restore %o5 and subtract from %o3.
+               sll     %g1, 4, %g1     ! high order bit
+               srl     %o5, 1, %o5             ! rest of %o5
+               add     %o5, %g1, %o5
+               b       Ldo_single_div
+               sub     %g7, 1, %g7
+
+       Lnot_too_big:
+       3:      cmp     %o5, %o3
+               blu     2b
+               nop
+               be      Ldo_single_div
+               nop
+       /* NB: these are commented out in the V8-Sparc manual as well */
+       /* (I do not understand this) */
+       ! %o5 > %o3: went too far: back up 1 step
+       !       srl     %o5, 1, %o5
+       !       dec     %g7
+       ! do single-bit divide steps
+       !
+       ! We have to be careful here.  We know that %o3 >= %o5, so we can do the
+       ! first divide step without thinking.  BUT, the others are conditional,
+       ! and are only done if %o3 >= 0.  Because both %o3 and %o5 may have the high-
+       ! order bit set in the first step, just falling into the regular
+       ! division loop will mess up the first time around.
+       ! So we unroll slightly...
+       Ldo_single_div:
+               subcc   %g7, 1, %g7
+               bl      Lend_regular_divide
+               nop
+               sub     %o3, %o5, %o3
+               mov     1, %o2
+               b       Lend_single_divloop
+               nop
+       Lsingle_divloop:
+               sll     %o2, 1, %o2
+               bl      1f
+               srl     %o5, 1, %o5
+               ! %o3 >= 0
+               sub     %o3, %o5, %o3
+               b       2f
+               add     %o2, 1, %o2
+       1:      ! %o3 < 0
+               add     %o3, %o5, %o3
+               sub     %o2, 1, %o2
+       2:
+       Lend_single_divloop:
+               subcc   %g7, 1, %g7
+               bge     Lsingle_divloop
+               tst     %o3
+               b,a     Lend_regular_divide
+
+Lnot_really_big:
+1:
+       sll     %o5, 4, %o5
+       cmp     %o5, %o3
+       bleu    1b
+       addcc   %o4, 1, %o4
+       be      Lgot_result
+       sub     %o4, 1, %o4
+
+       tst     %o3     ! set up for initial iteration
+Ldivloop:
+       sll     %o2, 4, %o2
+               ! depth 1, accumulated bits 0
+       bl      L.1.16
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits 1
+       bl      L.2.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 3
+       bl      L.3.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 7
+       bl      L.4.23
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2+1), %o2
+       
+L.4.23:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2-1), %o2
+       
+       
+L.3.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 5
+       bl      L.4.21
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2+1), %o2
+       
+L.4.21:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2-1), %o2
+       
+       
+       
+L.2.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 1
+       bl      L.3.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 3
+       bl      L.4.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2+1), %o2
+       
+L.4.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2-1), %o2
+       
+       
+L.3.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 1
+       bl      L.4.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2+1), %o2
+       
+L.4.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2-1), %o2
+       
+       
+       
+       
+L.1.16:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits -1
+       bl      L.2.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -1
+       bl      L.3.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -1
+       bl      L.4.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2+1), %o2
+       
+L.4.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2-1), %o2
+       
+       
+L.3.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -3
+       bl      L.4.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2+1), %o2
+       
+L.4.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2-1), %o2
+       
+       
+       
+L.2.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -3
+       bl      L.3.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -5
+       bl      L.4.11
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2+1), %o2
+       
+L.4.11:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2-1), %o2
+       
+       
+L.3.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -7
+       bl      L.4.9
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2+1), %o2
+       
+L.4.9:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2-1), %o2
+       
+       
+       
+       
+       9:
+Lend_regular_divide:
+       subcc   %o4, 1, %o4
+       bge     Ldivloop
+       tst     %o3
+       bl,a    Lgot_result
+       ! non-restoring fixup here (one instruction only!)
+       sub     %o2, 1, %o2
+
+
+Lgot_result:
+       ! check to see if answer should be < 0
+       tst     %g6
+       bl,a    1f
+       sub %g0, %o2, %o2
+1:
+       retl
+       mov %o2, %o0
diff --git a/ldso/ldso/sparc/sysdep.h b/ldso/ldso/sparc/sysdep.h
new file mode 100644 (file)
index 0000000..1d4c035
--- /dev/null
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table.  This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X)     __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.  We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT.  For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots.  The PLT should
+ * look like:
+ *
+ *             save %sp, -64, %sp
+ *             call _dl_linux_resolve
+ *             nop
+ *             .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{                              \
+   GOT_BASE[0] = 0x9de3bfc0;  /* save %sp, -64, %sp */ \
+   GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+   GOT_BASE[2] = 0x01000000; /* nop */                         \
+   GOT_BASE[3] = (int) MODULE;                                 \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+       switch(ELF32_R_TYPE((RELP)->r_info)) {          \
+       case R_SPARC_32:                                \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_GLOB_DAT:                          \
+         *REL = SYMBOL + (RELP)->r_addend;             \
+         break;                                        \
+       case R_SPARC_JMP_SLOT:                          \
+         REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff);    \
+         REL[2] = 0x81c06000 | (SYMBOL & 0x3ff);       \
+         break;                                        \
+       case R_SPARC_NONE:                              \
+         break;                                        \
+        case R_SPARC_WDISP30:                          \
+          break;                                        \
+       case R_SPARC_RELATIVE:                          \
+         *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+         break;                                        \
+       default:                                        \
+         _dl_exit(1);                                  \
+       }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START()                \
+       __asm__ volatile ( \
+                          "add %%g0,%%g0,%%g1\n\t" \
+                          "jmpl %0, %%o7\n\t"  \
+                          "restore %%g0,%%g0,%%g0\n\t" \
+                       : /*"=r" (status) */ :  \
+                         "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+                                       unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv.  This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+       "sdiv %2,%3,%%l6\n\t" \
+        "smul %%l6,%3,%%l6\n\t" \
+        "sub  %2,%%l6,%0\n\t" \
+        :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name.  Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/udiv.S b/ldso/ldso/sparc/udiv.S
new file mode 100644 (file)
index 0000000..df4e538
--- /dev/null
@@ -0,0 +1,351 @@
+   /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ *  .udiv      name of function to generate
+ *  div                div=div => %o0 / %o1; div=rem => %o0 % %o1
+ *  false              false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ *  N          how many bits per iteration we try to get (4)
+ *  WORDSIZE   total number of bits (32)
+ *
+ * Derived constants:
+ *  TOPBITS    number of bits in the top decade of a number
+ *
+ * Important variables:
+ *  Q          the partial quotient under development (initially 0)
+ *  R          the remainder so far, initially the dividend
+ *  ITER       number of main division loop iterations required;
+ *             equal to ceil(log2(quotient) / N).  Note that this
+ *             is the log base (2^N) of the quotient.
+ *  V          the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ *  Current estimate for non-large dividend is
+ *     ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ *  A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ *  different path, as the upper bits of the quotient must be developed
+ *  one bit at a time.
+ */
+
+
+#include "DEFS.h"
+#ifndef __linux__
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#else
+#include <asm/traps.h>
+#endif
+
+FUNC(_dl_udiv)
+
+       ! Ready to divide.  Compute size of quotient; scale comparand.
+       orcc    %o1, %g0, %o5
+       bne     1f
+       mov     %o0, %o3
+
+               ! Divide by zero trap.  If it returns, return 0 (about as
+               ! wrong as possible, but that is what SunOS does...).
+               ta      ST_DIV0
+               retl
+               clr     %o0
+
+1:
+       cmp     %o3, %o5                        ! if %o1 exceeds %o0, done
+       blu     Lgot_result             ! (and algorithm fails otherwise)
+       clr     %o2
+       sethi   %hi(1 << (32 - 4 - 1)), %g1
+       cmp     %o3, %g1
+       blu     Lnot_really_big
+       clr     %o4
+
+       ! Here the dividend is >= 2**(31-N) or so.  We must be careful here,
+       ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+       ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+       ! Compute ITER in an unorthodox manner: know we need to shift V into
+       ! the top decade: so do not even bother to compare to R.
+       1:
+               cmp     %o5, %g1
+               bgeu    3f
+               mov     1, %g7
+               sll     %o5, 4, %o5
+               b       1b
+               add     %o4, 1, %o4
+
+       ! Now compute %g7.
+       2:      addcc   %o5, %o5, %o5
+               bcc     Lnot_too_big
+               add     %g7, 1, %g7
+
+               ! We get here if the %o1 overflowed while shifting.
+               ! This means that %o3 has the high-order bit set.
+               ! Restore %o5 and subtract from %o3.
+               sll     %g1, 4, %g1     ! high order bit
+               srl     %o5, 1, %o5             ! rest of %o5
+               add     %o5, %g1, %o5
+               b       Ldo_single_div
+               sub     %g7, 1, %g7
+
+       Lnot_too_big:
+       3:      cmp     %o5, %o3
+               blu     2b
+               nop
+               be      Ldo_single_div
+               nop
+       /* NB: these are commented out in the V8-Sparc manual as well */
+       /* (I do not understand this) */
+       ! %o5 > %o3: went too far: back up 1 step
+       !       srl     %o5, 1, %o5
+       !       dec     %g7
+       ! do single-bit divide steps
+       !
+       ! We have to be careful here.  We know that %o3 >= %o5, so we can do the
+       ! first divide step without thinking.  BUT, the others are conditional,
+       ! and are only done if %o3 >= 0.  Because both %o3 and %o5 may have the high-
+       ! order bit set in the first step, just falling into the regular
+       ! division loop will mess up the first time around.
+       ! So we unroll slightly...
+       Ldo_single_div:
+               subcc   %g7, 1, %g7
+               bl      Lend_regular_divide
+               nop
+               sub     %o3, %o5, %o3
+               mov     1, %o2
+               b       Lend_single_divloop
+               nop
+       Lsingle_divloop:
+               sll     %o2, 1, %o2
+               bl      1f
+               srl     %o5, 1, %o5
+               ! %o3 >= 0
+               sub     %o3, %o5, %o3
+               b       2f
+               add     %o2, 1, %o2
+       1:      ! %o3 < 0
+               add     %o3, %o5, %o3
+               sub     %o2, 1, %o2
+       2:
+       Lend_single_divloop:
+               subcc   %g7, 1, %g7
+               bge     Lsingle_divloop
+               tst     %o3
+               b,a     Lend_regular_divide
+
+Lnot_really_big:
+1:
+       sll     %o5, 4, %o5
+       cmp     %o5, %o3
+       bleu    1b
+       addcc   %o4, 1, %o4
+       be      Lgot_result
+       sub     %o4, 1, %o4
+
+       tst     %o3     ! set up for initial iteration
+Ldivloop:
+       sll     %o2, 4, %o2
+               ! depth 1, accumulated bits 0
+       bl      L.1.16
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits 1
+       bl      L.2.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 3
+       bl      L.3.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 7
+       bl      L.4.23
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2+1), %o2
+       
+L.4.23:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2-1), %o2
+       
+       
+L.3.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 5
+       bl      L.4.21
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2+1), %o2
+       
+L.4.21:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2-1), %o2
+       
+       
+       
+L.2.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 1
+       bl      L.3.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 3
+       bl      L.4.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2+1), %o2
+       
+L.4.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2-1), %o2
+       
+       
+L.3.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 1
+       bl      L.4.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2+1), %o2
+       
+L.4.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2-1), %o2
+       
+       
+       
+       
+L.1.16:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits -1
+       bl      L.2.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -1
+       bl      L.3.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -1
+       bl      L.4.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2+1), %o2
+       
+L.4.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2-1), %o2
+       
+       
+L.3.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -3
+       bl      L.4.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2+1), %o2
+       
+L.4.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2-1), %o2
+       
+       
+       
+L.2.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -3
+       bl      L.3.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -5
+       bl      L.4.11
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2+1), %o2
+       
+L.4.11:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2-1), %o2
+       
+       
+L.3.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -7
+       bl      L.4.9
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2+1), %o2
+       
+L.4.9:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2-1), %o2
+       
+       
+       
+       
+       9:
+Lend_regular_divide:
+       subcc   %o4, 1, %o4
+       bge     Ldivloop
+       tst     %o3
+       bl,a    Lgot_result
+       ! non-restoring fixup here (one instruction only!)
+       sub     %o2, 1, %o2
+
+
+Lgot_result:
+
+       retl
+       mov %o2, %o0
diff --git a/ldso/ldso/sparc/umul.S b/ldso/ldso/sparc/umul.S
new file mode 100644 (file)
index 0000000..7a26c29
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Unsigned multiply.  Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
+ * upper 32 bits of the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies.  Short
+ * multiplies require 25 instruction cycles, and long ones require
+ * 45 instruction cycles.
+ *
+ * On return, overflow has occurred (%o1 is not zero) if and only if
+ * the Z condition code is clear, allowing, e.g., the following:
+ *
+ *     call    .umul
+ *     nop
+ *     bnz     overflow        (or tnz)
+ */
+
+#include "DEFS.h"
+FUNC(.umul)
+       or      %o0, %o1, %o4
+       mov     %o0, %y         ! multiplier -> Y
+       andncc  %o4, 0xfff, %g0 ! test bits 12..31 of *both* args
+       be      Lmul_shortway   ! if zero, can do it the short way
+       andcc   %g0, %g0, %o4   ! zero the partial product and clear N and V
+
+       /*
+        * Long multiply.  32 steps, followed by a final shift step.
+        */
+       mulscc  %o4, %o1, %o4   ! 1
+       mulscc  %o4, %o1, %o4   ! 2
+       mulscc  %o4, %o1, %o4   ! 3
+       mulscc  %o4, %o1, %o4   ! 4
+       mulscc  %o4, %o1, %o4   ! 5
+       mulscc  %o4, %o1, %o4   ! 6
+       mulscc  %o4, %o1, %o4   ! 7
+       mulscc  %o4, %o1, %o4   ! 8
+       mulscc  %o4, %o1, %o4   ! 9
+       mulscc  %o4, %o1, %o4   ! 10
+       mulscc  %o4, %o1, %o4   ! 11
+       mulscc  %o4, %o1, %o4   ! 12
+       mulscc  %o4, %o1, %o4   ! 13
+       mulscc  %o4, %o1, %o4   ! 14
+       mulscc  %o4, %o1, %o4   ! 15
+       mulscc  %o4, %o1, %o4   ! 16
+       mulscc  %o4, %o1, %o4   ! 17
+       mulscc  %o4, %o1, %o4   ! 18
+       mulscc  %o4, %o1, %o4   ! 19
+       mulscc  %o4, %o1, %o4   ! 20
+       mulscc  %o4, %o1, %o4   ! 21
+       mulscc  %o4, %o1, %o4   ! 22
+       mulscc  %o4, %o1, %o4   ! 23
+       mulscc  %o4, %o1, %o4   ! 24
+       mulscc  %o4, %o1, %o4   ! 25
+       mulscc  %o4, %o1, %o4   ! 26
+       mulscc  %o4, %o1, %o4   ! 27
+       mulscc  %o4, %o1, %o4   ! 28
+       mulscc  %o4, %o1, %o4   ! 29
+       mulscc  %o4, %o1, %o4   ! 30
+       mulscc  %o4, %o1, %o4   ! 31
+       mulscc  %o4, %o1, %o4   ! 32
+       mulscc  %o4, %g0, %o4   ! final shift
+
+
+       /*
+        * Normally, with the shift-and-add approach, if both numbers are
+        * positive you get the correct result.  With 32-bit two's-complement
+        * numbers, -x is represented as
+        *
+        *                x                 32
+        *      ( 2  -  ------ ) mod 2  *  2
+        *                 32
+        *                2
+        *
+        * (the `mod 2' subtracts 1 from 1.bbbb).  To avoid lots of 2^32s,
+        * we can treat this as if the radix point were just to the left
+        * of the sign bit (multiply by 2^32), and get
+        *
+        *      -x  =  (2 - x) mod 2
+        *
+        * Then, ignoring the `mod 2's for convenience:
+        *
+        *   x *  y     = xy
+        *  -x *  y     = 2y - xy
+        *   x * -y     = 2x - xy
+        *  -x * -y     = 4 - 2x - 2y + xy
+        *
+        * For signed multiplies, we subtract (x << 32) from the partial
+        * product to fix this problem for negative multipliers (see mul.s).
+        * Because of the way the shift into the partial product is calculated
+        * (N xor V), this term is automatically removed for the multiplicand,
+        * so we don't have to adjust.
+        *
+        * But for unsigned multiplies, the high order bit wasn't a sign bit,
+        * and the correction is wrong.  So for unsigned multiplies where the
+        * high order bit is one, we end up with xy - (y << 32).  To fix it
+        * we add y << 32.
+        */
+#if 0
+       tst     %o1
+       bl,a    1f              ! if %o1 < 0 (high order bit = 1),
+       add     %o4, %o0, %o4   ! %o4 += %o0 (add y to upper half)
+1:     rd      %y, %o0         ! get lower half of product
+       retl
+       addcc   %o4, %g0, %o1   ! put upper half in place and set Z for %o1==0
+#else
+       /* Faster code from tege@sics.se.  */
+       sra     %o1, 31, %o2    ! make mask from sign bit
+       and     %o0, %o2, %o2   ! %o2 = 0 or %o0, depending on sign of %o1
+       rd      %y, %o0         ! get lower half of product
+       retl
+       addcc   %o4, %o2, %o1   ! add compensation and put upper half in place
+#endif
+
+Lmul_shortway:
+       /*
+        * Short multiply.  12 steps, followed by a final shift step.
+        * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+        * but there is no problem with %o0 being negative (unlike above),
+        * and overflow is impossible (the answer is at most 24 bits long).
+        */
+       mulscc  %o4, %o1, %o4   ! 1
+       mulscc  %o4, %o1, %o4   ! 2
+       mulscc  %o4, %o1, %o4   ! 3
+       mulscc  %o4, %o1, %o4   ! 4
+       mulscc  %o4, %o1, %o4   ! 5
+       mulscc  %o4, %o1, %o4   ! 6
+       mulscc  %o4, %o1, %o4   ! 7
+       mulscc  %o4, %o1, %o4   ! 8
+       mulscc  %o4, %o1, %o4   ! 9
+       mulscc  %o4, %o1, %o4   ! 10
+       mulscc  %o4, %o1, %o4   ! 11
+       mulscc  %o4, %o1, %o4   ! 12
+       mulscc  %o4, %g0, %o4   ! final shift
+
+       /*
+        * %o4 has 20 of the bits that should be in the result; %y has
+        * the bottom 12 (as %y's top 12).  That is:
+        *
+        *        %o4               %y
+        * +----------------+----------------+
+        * | -12- |   -20-  | -12- |   -20-  |
+        * +------(---------+------)---------+
+        *         -----result-----
+        *
+        * The 12 bits of %o4 left of the `result' area are all zero;
+        * in fact, all top 20 bits of %o4 are zero.
+        */
+
+       rd      %y, %o5
+       sll     %o4, 12, %o0    ! shift middle bits left 12
+       srl     %o5, 20, %o5    ! shift low bits right 20
+       or      %o5, %o0, %o0
+       retl
+       addcc   %g0, %g0, %o1   ! %o1 = zero, and set Z
diff --git a/ldso/ldso/sparc/urem.S b/ldso/ldso/sparc/urem.S
new file mode 100644 (file)
index 0000000..8d30403
--- /dev/null
@@ -0,0 +1,352 @@
+   /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ *  .urem      name of function to generate
+ *  rem                rem=div => %o0 / %o1; rem=rem => %o0 % %o1
+ *  false              false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ *  N          how many bits per iteration we try to get (4)
+ *  WORDSIZE   total number of bits (32)
+ *
+ * Derived constants:
+ *  TOPBITS    number of bits in the top decade of a number
+ *
+ * Important variables:
+ *  Q          the partial quotient under development (initially 0)
+ *  R          the remainder so far, initially the dividend
+ *  ITER       number of main division loop iterations required;
+ *             equal to ceil(log2(quotient) / N).  Note that this
+ *             is the log base (2^N) of the quotient.
+ *  V          the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ *  Current estimate for non-large dividend is
+ *     ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ *  A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ *  different path, as the upper bits of the quotient must be developed
+ *  one bit at a time.
+ */
+
+
+
+#include "DEFS.h"
+#ifdef __linux__
+#include <asm/traps.h>
+#else
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#endif
+
+FUNC(_dl_urem)
+
+       ! Ready to divide.  Compute size of quotient; scale comparand.
+       orcc    %o1, %g0, %o5
+       bne     1f
+       mov     %o0, %o3
+
+               ! Divide by zero trap.  If it returns, return 0 (about as
+               ! wrong as possible, but that is what SunOS does...).
+               ta      ST_DIV0
+               retl
+               clr     %o0
+
+1:
+       cmp     %o3, %o5                        ! if %o1 exceeds %o0, done
+       blu     Lgot_result             ! (and algorithm fails otherwise)
+       clr     %o2
+       sethi   %hi(1 << (32 - 4 - 1)), %g1
+       cmp     %o3, %g1
+       blu     Lnot_really_big
+       clr     %o4
+
+       ! Here the dividend is >= 2**(31-N) or so.  We must be careful here,
+       ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+       ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+       ! Compute ITER in an unorthodox manner: know we need to shift V into
+       ! the top decade: so do not even bother to compare to R.
+       1:
+               cmp     %o5, %g1
+               bgeu    3f
+               mov     1, %g7
+               sll     %o5, 4, %o5
+               b       1b
+               add     %o4, 1, %o4
+
+       ! Now compute %g7.
+       2:      addcc   %o5, %o5, %o5
+               bcc     Lnot_too_big
+               add     %g7, 1, %g7
+
+               ! We get here if the %o1 overflowed while shifting.
+               ! This means that %o3 has the high-order bit set.
+               ! Restore %o5 and subtract from %o3.
+               sll     %g1, 4, %g1     ! high order bit
+               srl     %o5, 1, %o5             ! rest of %o5
+               add     %o5, %g1, %o5
+               b       Ldo_single_div
+               sub     %g7, 1, %g7
+
+       Lnot_too_big:
+       3:      cmp     %o5, %o3
+               blu     2b
+               nop
+               be      Ldo_single_div
+               nop
+       /* NB: these are commented out in the V8-Sparc manual as well */
+       /* (I do not understand this) */
+       ! %o5 > %o3: went too far: back up 1 step
+       !       srl     %o5, 1, %o5
+       !       dec     %g7
+       ! do single-bit divide steps
+       !
+       ! We have to be careful here.  We know that %o3 >= %o5, so we can do the
+       ! first divide step without thinking.  BUT, the others are conditional,
+       ! and are only done if %o3 >= 0.  Because both %o3 and %o5 may have the high-
+       ! order bit set in the first step, just falling into the regular
+       ! division loop will mess up the first time around.
+       ! So we unroll slightly...
+       Ldo_single_div:
+               subcc   %g7, 1, %g7
+               bl      Lend_regular_divide
+               nop
+               sub     %o3, %o5, %o3
+               mov     1, %o2
+               b       Lend_single_divloop
+               nop
+       Lsingle_divloop:
+               sll     %o2, 1, %o2
+               bl      1f
+               srl     %o5, 1, %o5
+               ! %o3 >= 0
+               sub     %o3, %o5, %o3
+               b       2f
+               add     %o2, 1, %o2
+       1:      ! %o3 < 0
+               add     %o3, %o5, %o3
+               sub     %o2, 1, %o2
+       2:
+       Lend_single_divloop:
+               subcc   %g7, 1, %g7
+               bge     Lsingle_divloop
+               tst     %o3
+               b,a     Lend_regular_divide
+
+Lnot_really_big:
+1:
+       sll     %o5, 4, %o5
+       cmp     %o5, %o3
+       bleu    1b
+       addcc   %o4, 1, %o4
+       be      Lgot_result
+       sub     %o4, 1, %o4
+
+       tst     %o3     ! set up for initial iteration
+Ldivloop:
+       sll     %o2, 4, %o2
+               ! depth 1, accumulated bits 0
+       bl      L.1.16
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits 1
+       bl      L.2.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 3
+       bl      L.3.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 7
+       bl      L.4.23
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2+1), %o2
+       
+L.4.23:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (7*2-1), %o2
+       
+       
+L.3.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 5
+       bl      L.4.21
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2+1), %o2
+       
+L.4.21:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (5*2-1), %o2
+       
+       
+       
+L.2.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits 1
+       bl      L.3.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 3
+       bl      L.4.19
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2+1), %o2
+       
+L.4.19:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (3*2-1), %o2
+       
+       
+L.3.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits 1
+       bl      L.4.17
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2+1), %o2
+       
+L.4.17:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (1*2-1), %o2
+       
+       
+       
+       
+L.1.16:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 2, accumulated bits -1
+       bl      L.2.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -1
+       bl      L.3.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -1
+       bl      L.4.15
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2+1), %o2
+       
+L.4.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-1*2-1), %o2
+       
+       
+L.3.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -3
+       bl      L.4.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2+1), %o2
+       
+L.4.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-3*2-1), %o2
+       
+       
+       
+L.2.15:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 3, accumulated bits -3
+       bl      L.3.13
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -5
+       bl      L.4.11
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2+1), %o2
+       
+L.4.11:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-5*2-1), %o2
+       
+       
+L.3.13:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+                       ! depth 4, accumulated bits -7
+       bl      L.4.9
+       srl     %o5,1,%o5
+       ! remainder is positive
+       subcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2+1), %o2
+       
+L.4.9:
+       ! remainder is negative
+       addcc   %o3,%o5,%o3
+               b       9f
+               add     %o2, (-7*2-1), %o2
+       
+       
+       
+       
+       9:
+Lend_regular_divide:
+       subcc   %o4, 1, %o4
+       bge     Ldivloop
+       tst     %o3
+       bl,a    Lgot_result
+       ! non-restoring fixup here (one instruction only!)
+       add     %o3, %o1, %o3
+
+
+Lgot_result:
+
+       retl
+       mov %o3, %o0
diff --git a/ldso/ldso/string.h b/ldso/ldso/string.h
new file mode 100644 (file)
index 0000000..1ea8fd7
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h>       /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char * _dl_strcpy(char * dst,const char *src)
+{
+       register char *ptr = dst;
+
+       while (*src)
+               *dst++ = *src++;
+       *dst = '\0';
+
+       return ptr;
+}
+extern inline int _dl_strcmp(const char * s1,const char * s2)
+{
+       unsigned register char c1, c2;
+
+       do {
+               c1 = (unsigned char) *s1++;
+               c2 = (unsigned char) *s2++;
+               if (c1 == '\0')
+                       return c1 - c2;
+       }
+       while (c1 == c2);
+
+       return c1 - c2;
+}
+
+extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
+{
+       unsigned register char c1 = '\0';
+       unsigned register char c2 = '\0';
+
+       while (len > 0) {
+               c1 = (unsigned char) *s1++;
+               c2 = (unsigned char) *s2++;
+               if (c1 == '\0' || c1 != c2)
+                       return c1 - c2;
+               len--;
+       }
+
+       return c1 - c2;
+}
+
+extern inline char * _dl_strchr(const char * str,int c)
+{
+       register char ch;
+
+       do {
+               if ((ch = *str) == c)
+                       return (char *) str;
+               str++;
+       }
+       while (ch);
+
+       return 0;
+}
+
+
+extern inline size_t _dl_strlen(const char * str)
+{
+       register char *ptr = (char *) str;
+
+       while (*ptr)
+               ptr++;
+       return (ptr - str);
+}
+
+extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+       register char *a = dst;
+       register const char *b = src;
+
+       while (len--)
+               *a++ = *b++;
+
+       return dst;
+}
+
+
+extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
+{
+       unsigned char *c1 = (unsigned char *)s1;
+       unsigned char *c2 = (unsigned char *)s2;
+
+       while (len--) {
+               if (*c1 != *c2) 
+                       return *c1 - *c2;
+               c1++;
+               c2++;
+       }
+       return 0;
+}
+
+extern inline void * _dl_memset(void * str,int c,size_t len)
+{
+       register char *a = str;
+
+       while (len--)
+               *a++ = c;
+
+       return str;
+}
+
+#endif
diff --git a/ldso/ldso/syscall.h b/ldso/ldso/syscall.h
new file mode 100644 (file)
index 0000000..3cf2443
--- /dev/null
@@ -0,0 +1,108 @@
+#include <linux/types.h>
+#include <asm/unistd.h>
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+
+#define _dl_mmap_check_error(__res)    \
+       (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+
+
+/* Here are the definitions for some syscalls that are used
+   by the dynamic linker.  The idea is that we want to be able
+   to call these before the errno symbol is dynamicly linked, so
+   we use our own version here.  Note that we cannot assume any
+   dynamic linking at all, so we cannot return any error codes.
+   We just punt if there is an error. */
+
+/* Do not include unistd.h, so gcc doesn't whine about 
+ * _exit returning.  It really doesn't return... */
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+               int flags, int fd, unsigned long offset)
+{
+       unsigned long buffer[6];
+
+       buffer[0] = (unsigned long) addr;
+       buffer[1] = (unsigned long) size;
+       buffer[2] = (unsigned long) prot;
+       buffer[3] = (unsigned long) flags;
+       buffer[4] = (unsigned long) fd;
+       buffer[5] = (unsigned long) offset;
+       return (void *) _dl_mmap_real(buffer);
+}
+
+#define __NR__dl_open __NR_open
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd, 
+           const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd, 
+           const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like.  It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define __NR__dl_stat  __NR_stat
+#define stat kernel_stat
+#define new_stat kernel_stat
+#include <asm/stat.h> 
+#undef new_stat
+#undef stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(gid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+extern inline int _dl_suid_ok(void)
+{
+    uid_t uid, euid, gid, egid;
+
+    uid = _dl_getuid();
+    euid = _dl_geteuid();
+    gid = _dl_getgid();
+    egid = _dl_getegid();
+
+    if(uid == euid && gid == egid)
+       return 1;
+    else
+       return 0;
+}
+
diff --git a/ldso/ldso/vsprintf.c b/ldso/ldso/vsprintf.c
new file mode 100644 (file)
index 0000000..48c44e3
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *  vsprintf.c
+ *
+ *  Copyright (C) 1991-1996  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdarg.h>
+#include "string.h"
+#include "hash.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+
+/* we use this so that we can do without the ctype library */
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+       int i=0;
+
+       while (is_digit(**s))
+               i = i*10 + *((*s)++) - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#ifndef __sparc__
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+#else
+#define do_div(n,base) _dl_div ((n)/(base))
+#define do_div(n,base) ({ \
+int __res; \
+__res = _dl_urem(((unsigned long) n),(unsigned) base); \
+n = _dl_udiv(((unsigned long) n),(unsigned) base); \
+__res; })
+#endif
+
+#define ADD_CHAR(s,n,c) ( ((n) > 1) ? *(s)++ = (c), (n)-- : (c) )
+
+static char * number(char * str, int *bufsize, long num, int base, int size, int precision
+       ,int type)
+{
+       char c,sign,tmp[66];
+       const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+       int i;
+
+       if (type & LARGE)
+               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if (num < 0) {
+                       sign = '-';
+                       num = -num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0)
+               tmp[i++] = digits[do_div(num,base)];
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT)))
+               while(size-->0)
+                       ADD_CHAR(str, *bufsize, ' ');
+       if (sign)
+               ADD_CHAR(str, *bufsize, sign);
+       if (type & SPECIAL) {
+               if (base==8)
+                       ADD_CHAR(str, *bufsize, '0');
+               else if (base==16) {
+                       ADD_CHAR(str, *bufsize, '0');
+                       ADD_CHAR(str, *bufsize, digits[33]);
+               }
+       }
+       if (!(type & LEFT))
+               while (size-- > 0)
+                       ADD_CHAR(str, *bufsize, c);
+       while (i < precision--)
+               ADD_CHAR(str, *bufsize, '0');
+       while (i-- > 0)
+               ADD_CHAR(str, *bufsize, tmp[i]);
+       while (size-- > 0)
+               ADD_CHAR(str, *bufsize, ' ');
+       return str;
+}
+
+int _dl_fdprintf(int fd, const char *fmt, ...)
+{
+       int len;
+       unsigned long num;
+       int i, base;
+       char * str;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+
+       int bufsize;
+       char buf[2048];
+       va_list(args);
+
+       va_start(args, fmt);
+
+       for (str=buf, bufsize=sizeof buf ; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       ADD_CHAR(str, bufsize, *fmt);
+                       continue;
+               }
+                       
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                               }
+               
+               /* get field width */
+               field_width = -1;
+               if (is_digit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;  
+                       if (is_digit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+                       qualifier = *fmt;
+                       ++fmt;
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       ADD_CHAR(str, bufsize, ' ');
+                       ADD_CHAR(str, bufsize, (unsigned char) va_arg(args, int));
+                       while (--field_width > 0)
+                               ADD_CHAR(str, bufsize, ' ');
+                       continue;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       if (!s)
+                               s = "<NULL>";
+
+                       len = _dl_strlen(s);
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       ADD_CHAR(str, bufsize, ' ');
+                       for (i = 0; i < len; ++i)
+                               ADD_CHAR(str, bufsize, *s++);
+                       while (len < field_width--)
+                               ADD_CHAR(str, bufsize, ' ');
+                       continue;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 2*sizeof(void *);
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str, &bufsize,
+                               (unsigned long) va_arg(args, void *), 16,
+                               field_width, precision, flags);
+                       continue;
+
+
+               case 'n':
+                       if (qualifier == 'l') {
+                               long * ip = va_arg(args, long *);
+                               *ip = (str - buf);
+                       } else {
+                               int * ip = va_arg(args, int *);
+                               *ip = (str - buf);
+                       }
+                       continue;
+
+               /* integer number formats - set up the flags and "break" */
+               case 'o':
+                       base = 8;
+                       break;
+
+               case 'X':
+                       flags |= LARGE;
+               case 'x':
+                       base = 16;
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       break;
+
+               default:
+                       if (*fmt != '%')
+                               ADD_CHAR(str, bufsize, '%');
+                       if (*fmt)
+                               ADD_CHAR(str, bufsize, *fmt);
+                       else
+                               --fmt;
+                       continue;
+               }
+               if (qualifier == 'l')
+                       num = va_arg(args, unsigned long);
+               else if (qualifier == 'h')
+                       if (flags & SIGN)
+                               num = va_arg(args, short);
+                       else
+                               num = va_arg(args, unsigned short);
+               else if (flags & SIGN)
+                       num = va_arg(args, int);
+               else
+                       num = va_arg(args, unsigned int);
+               str = number(str, &bufsize, num, base, field_width, precision, flags);
+       }
+       *str = '\0';
+       _dl_write(fd, buf, str-buf);
+       return str-buf;
+}
+
diff --git a/ldso/libdl/Makefile b/ldso/libdl/Makefile
new file mode 100644 (file)
index 0000000..8578357
--- /dev/null
@@ -0,0 +1,31 @@
+TOPDIR=../../../
+include $(TOPDIR)Rules.mak
+include $(TOPDIR)/ld.so-1/Config.mk
+
+CFLAGS += -DNO_UNDERSCORE -DVERBOSE_DLINKER -DUSE_CACHE
+CFLAGS += #-fPIC -D__PIC__ #-funroll-loops
+
+LIBDL = libdl.so
+
+CSRC= dlib.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+OBJS=$(COBJS)
+
+$(COBJS): %.o : %.c
+       $(CC) -I.. -I../$(TARGET_ARCH) $(CFLAGS) -c $< -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+ELF_LDFLAGS=--shared -nostartfiles -nostdlib # using GNU ld
+#ELF_LDFLAGS=-G  # with SVr4 ld
+
+lib:: $(OBJS)
+       $(CC) $(ELF_LDFLAGS) -o $(LIBDL).$(LDSO_VMAJOR) \
+                -Wl,-soname -Wl,$(LIBDL).$(LDSO_VMAJOR) *.o -lc
+
+obj: $(OBJS)
+
+realclean::
+       $(RM) -f .depend $(LIBDL) core *.o *.a *.s *.i tmp_make foo *~
+
+clean::
+       $(RM) -f $(LIBDL) core *.o *.a *.s *.i tmp_make foo *~
diff --git a/ldso/libdl/dlfcn.h b/ldso/libdl/dlfcn.h
new file mode 100644 (file)
index 0000000..6201811
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef DLFCN_H
+#define DLFCN_H
+
+#include <features.h>
+
+/*
+ * Various defines and so forth for the dynamic linker
+ */
+
+/* For dlopen () */
+#define RTLD_LAZY      1
+#define RTLD_NOW       2
+#define RTLD_GLOBAL    0x100
+
+/* For dlsym */
+#define RTLD_NEXT      ((void *)-1)
+
+__BEGIN_DECLS
+
+/* The usual prototypes.  We use void * instead of the actual
+ * datatype - the user does not manipulate the handles at all.
+ */
+extern void * dlopen __P((__const char * __filename, int __flag));
+extern __const char * dlerror __P((void));
+extern void * dlsym __P((void *, __const char *));
+extern int dlclose __P((void *));
+
+typedef struct
+{
+  const char *   dli_fname;   /* filename */
+  void *         dli_fbase;   /*  base address of object */
+  const char *   dli_sname;   /* nearest symbol name */
+  void *         dli_saddr;   /* nearest symbol address */
+} Dl_info;
+
+extern int dladdr __P((void * __address, Dl_info * __dlip )); 
+
+__END_DECLS
+
+#endif
diff --git a/ldso/libdl/dlib.c b/ldso/libdl/dlib.c
new file mode 100644 (file)
index 0000000..545b674
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * libdl.c
+ * 
+ * Functions required for dlopen et. al.
+ */
+
+#include "dlfcn.h"
+/* #include "link.h" */
+#include <stdlib.h>
+#include <linux/mman.h>
+#include <linux/unistd.h>
+#include "sysdep.h"
+#include "syscall.h"
+#include "hash.h"
+#include "string.h"
+#include "linuxelf.h"
+
+extern int _dl_error_number;
+extern struct r_debug * _dl_debug_addr;
+
+extern void * (*_dl_malloc_function)(size_t size);
+
+static int do_fixup(struct elf_resolve * tpnt, int flag);
+static int do_dlclose(void *, int need_fini);
+
+void * _dlopen(char * filename, int flag);
+const char * _dlerror(void);
+void * _dlsym(void *, char *);
+int _dlclose(void *);
+int _dladdr(void * __address, Dl_info * __dlip );
+
+static const char * dl_error_names[] = {
+       "",
+       "File not found",
+       "Unable to open /dev/zero",
+       "Not an ELF file",
+#if defined (__i386__)
+       "Not i386 binary",
+#elif defined (__sparc__)
+       "Not sparc binary",
+#elif defined (__mc68000__)
+       "Not m68k binary",
+#else
+       "Unrecognized binary type",
+#endif
+       "Not an ELF shared library",
+       "Unable to mmap file",
+       "No dynamic section",
+#ifdef ELF_USES_RELOCA
+       "Unable to process REL relocs",
+#else
+       "Unable to process RELA relocs",
+#endif
+       "Bad handle",
+       "Unable to resolve symbol"
+};
+       
+static void dl_cleanup(void) __attribute__ ((destructor));
+
+static void dl_cleanup(void)
+{
+       struct dyn_elf*         d;
+       
+       for (d = _dl_handles; d; d = d->next_handle)
+               if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI])
+               {
+                       (*((int(*)(void))(d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI])))();
+                       d->dyn->dynamic_info[DT_FINI] = 0;
+               }
+}
+
+void * _dlopen(char * libname, int flag)
+{
+       struct elf_resolve * tpnt, *tfrom;
+       struct dyn_elf * rpnt;
+       struct dyn_elf * dyn_chain;
+       struct dyn_elf * dpnt;
+       static int dl_init = 0;
+       char *  from;
+       void (*dl_brk)(void);
+       int (*dl_elf_init)(void);
+
+       from = __builtin_return_address(0);
+
+       /* Have the dynamic linker use the regular malloc function now */
+       if (!dl_init) {
+               dl_init++;
+               _dl_malloc_function = malloc;
+       }
+
+       /* Cover the trivial case first */
+       if (!libname) return _dl_symbol_tables;
+
+#ifdef USE_CACHE
+       _dl_map_cache();
+#endif
+
+       /*
+        * Try and locate the module we were called from - we
+        * need this so that we get the correct RPATH.  Note that
+        * this is the current behavior under Solaris, but the
+        * ABI+ specifies that we should only use the RPATH from
+        * the application.  Thus this may go away at some time
+        * in the future.
+        */
+       tfrom = NULL;
+       for(dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next)
+         {
+           tpnt = dpnt->dyn;
+           if(   tpnt->loadaddr < from 
+              && (   tfrom == NULL
+                  || tfrom->loadaddr < tpnt->loadaddr))
+             tfrom = tpnt;
+         }
+
+       if(!(tpnt = _dl_load_shared_library(0, tfrom, libname)))
+       {
+#ifdef USE_CACHE
+         _dl_unmap_cache();
+#endif
+         return NULL;
+       }
+
+       tpnt->usage_count++;
+       dyn_chain = rpnt = 
+          (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+       _dl_memset (rpnt, 0, sizeof(*rpnt));
+       rpnt->dyn = tpnt;
+       rpnt->flags = flag;
+       if (!tpnt->symbol_scope) tpnt->symbol_scope = dyn_chain;
+       
+       rpnt->next_handle = _dl_handles;
+       _dl_handles = rpnt;
+
+       /*
+        * OK, we have the requested file in memory.  Now check for
+        * any other requested files that may also be required.
+        */
+         {
+           struct elf_resolve *tcurr;
+           struct elf_resolve * tpnt1;
+           struct dynamic * dpnt;
+           char * lpnt;
+
+           tcurr = tpnt;
+           do{
+             for(dpnt = (struct dynamic *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+               {
+         
+                 if(dpnt->d_tag == DT_NEEDED)
+                   {
+                     lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
+                       dpnt->d_un.d_val;
+                     if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
+                       goto oops;
+
+                     rpnt->next = 
+                        (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+                     _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+                     rpnt = rpnt->next;
+                     tpnt1->usage_count++;
+                     if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
+                     rpnt->dyn = tpnt1;
+                   };
+               }
+             
+             tcurr = tcurr->next;
+           } while(tcurr);
+         }
+        
+       /*
+        * OK, now attach the entire chain at the end
+        */
+
+       rpnt->next = _dl_symbol_tables;
+
+       if (do_fixup(tpnt, flag)) {
+         _dl_error_number = DL_NO_SYMBOL;
+         goto oops;
+       }
+
+       dl_brk = (void (*)()) _dl_debug_addr->r_brk;
+       if( dl_brk != NULL )
+         {
+           _dl_debug_addr->r_state = RT_ADD;
+           (*dl_brk)();
+           
+           _dl_debug_addr->r_state = RT_CONSISTENT;
+           (*dl_brk)();
+         }
+
+       for(rpnt = dyn_chain; rpnt; rpnt = rpnt->next)
+       {
+               tpnt = rpnt->dyn;
+             /* Apparently crt1 for the application is responsible for handling this.
+              * We only need to run the init/fini for shared libraries
+              */
+             if (tpnt->libtype == elf_executable) continue;
+             if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
+             tpnt->init_flag |= INIT_FUNCS_CALLED;
+      
+             if(tpnt->dynamic_info[DT_INIT]) {
+               dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
+                                           tpnt->dynamic_info[DT_INIT]);
+               (*dl_elf_init)();
+             }
+       }
+
+#ifdef USE_CACHE
+       _dl_unmap_cache();
+#endif
+       return (void *) dyn_chain;
+
+oops:
+       /* Something went wrong.  Clean up and return NULL. */
+#ifdef USE_CACHE
+       _dl_unmap_cache();
+#endif
+       do_dlclose (dyn_chain, 0);
+       return NULL;
+}
+
+static int do_fixup(struct elf_resolve * tpnt, int flag)
+{
+  int goof = 0;
+  if(tpnt->next) goof += do_fixup(tpnt->next, flag);
+
+  if(tpnt->dynamic_info[DT_REL]) {
+#ifdef ELF_USES_RELOCA
+    goof++;
+#else
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+                                            tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+                                            tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+    goof++;
+#endif
+  }
+  if(tpnt->dynamic_info[DT_JMPREL])
+    {
+      if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
+      tpnt->init_flag |= JMP_RELOCS_DONE;
+      
+      if(flag == RTLD_LAZY)
+       _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+                                             tpnt->dynamic_info[DT_PLTRELSZ], 0);
+      else
+       goof +=  _dl_parse_relocation_information(tpnt,
+                                                 tpnt->dynamic_info[DT_JMPREL],
+                                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
+    };
+  return goof;
+}
+
+void * _dlsym(void * vhandle, char * name)
+{      
+       struct elf_resolve * tpnt, *tfrom;
+       struct dyn_elf * handle;
+       char *  from;
+       struct dyn_elf * rpnt;
+       void *ret;
+
+       handle = (struct dyn_elf *) vhandle;
+
+       /* First of all verify that we have a real handle
+       of some kind.  Return NULL if not a valid handle. */
+
+       if (handle == NULL)
+               handle = _dl_symbol_tables;
+       else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
+               for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
+                       if (rpnt == handle) break;
+               if (!rpnt) {
+                       _dl_error_number = DL_BAD_HANDLE;
+                       return NULL;
+               }
+       }
+       else if (handle == RTLD_NEXT )
+         {
+           /*
+            * Try and locate the module we were called from - we
+            * need this so that we know where to start searching
+            * from.  We never pass RTLD_NEXT down into the actual
+            * dynamic loader itself, as it doesn't know
+            * how to properly treat it.
+            */
+           from = __builtin_return_address(0);
+
+           tfrom = NULL;
+           for(rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
+             {
+               tpnt = rpnt->dyn;
+               if(   tpnt->loadaddr < from 
+                     && (   tfrom == NULL
+                            || tfrom->loadaddr < tpnt->loadaddr))
+                 {
+                   tfrom = tpnt;
+                   handle = rpnt->next;
+                 }
+             }
+         }
+
+       ret = _dl_find_hash(name, handle, 1, NULL, 1);
+
+       /*
+        * Nothing found.
+        */
+       if (!ret)
+               _dl_error_number = DL_NO_SYMBOL;
+       return ret;
+}
+
+int _dlclose(void * vhandle)
+{
+  return do_dlclose(vhandle, 1);
+}
+
+static int do_dlclose(void * vhandle, int need_fini)
+{
+       struct dyn_elf * rpnt, *rpnt1;
+       struct dyn_elf *spnt, *spnt1;
+       struct elf_phdr * ppnt;
+       struct elf_resolve * tpnt;
+       int (*dl_elf_fini)(void);
+       void (*dl_brk)(void);
+       struct dyn_elf * handle;
+       unsigned int end;
+       int i = 0;
+
+       handle = (struct dyn_elf *) vhandle;
+       rpnt1 = NULL;
+       for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
+       {
+               if(rpnt == handle) {
+                       break;
+               }
+               rpnt1 = rpnt;
+       }
+       
+       if (!rpnt) {
+               _dl_error_number = DL_BAD_HANDLE;
+               return 1;
+       }
+
+       /* OK, this is a valid handle - now close out the file.
+        * We check if we need to call fini () on the handle. */
+       spnt = need_fini ? handle : handle->next;
+       for(; spnt; spnt = spnt1)
+       {
+           spnt1 = spnt->next;
+
+           /* We appended the module list to the end - when we get back here, 
+            quit. The access counts were not adjusted to account for being here. */
+           if (spnt == _dl_symbol_tables) break;
+           if(spnt->dyn->usage_count==1 && spnt->dyn->libtype == loaded_file) {
+               tpnt = spnt->dyn;
+               /* Apparently crt1 for the application is responsible for handling this.
+                * We only need to run the init/fini for shared libraries
+                */
+
+               if(tpnt->dynamic_info[DT_FINI]) {
+                   dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
+                                                  tpnt->dynamic_info[DT_FINI]);
+                   (*dl_elf_fini)();
+               }       
+           }
+       }
+       if(rpnt1)
+           rpnt1->next_handle = rpnt->next_handle;
+       else
+           _dl_handles = rpnt->next_handle;
+       
+       /* OK, this is a valid handle - now close out the file */
+       for(rpnt = handle; rpnt; rpnt = rpnt1)
+         {
+               rpnt1 = rpnt->next;
+
+               /* We appended the module list to the end - when we get back here, 
+                  quit. The access counts were not adjusted to account for being here. */
+               if (rpnt == _dl_symbol_tables) break;
+
+               rpnt->dyn->usage_count--;
+               if(rpnt->dyn->usage_count == 0 && rpnt->dyn->libtype == loaded_file)
+               {
+                       tpnt = rpnt->dyn;
+                     /* Apparently crt1 for the application is responsible for handling this.
+                      * We only need to run the init/fini for shared libraries
+                      */
+#if 0
+/* We have to do this above, before we start closing objects.
+Otherwise when the needed symbols for _fini handling are
+resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
+                     if(tpnt->dynamic_info[DT_FINI]) {
+                       dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
+                                                   tpnt->dynamic_info[DT_FINI]);
+                       (*dl_elf_fini)();
+                     } 
+#endif
+                     end = 0;
+                       for(i = 0, ppnt = rpnt->dyn->ppnt; 
+                               i < rpnt->dyn->n_phent; ppnt++, i++) {
+                               if (ppnt->p_type != PT_LOAD) continue;
+                               if (end < ppnt->p_vaddr + ppnt->p_memsz)
+                                       end = ppnt->p_vaddr + ppnt->p_memsz;
+                       }
+                       _dl_munmap (rpnt->dyn->loadaddr, end);
+                       /* Next, remove rpnt->dyn from the loaded_module list */
+                       if (_dl_loaded_modules == rpnt->dyn)
+                       {
+                         _dl_loaded_modules = rpnt->dyn->next;
+                         if (_dl_loaded_modules)
+                           _dl_loaded_modules->prev = 0;
+                       }
+                       else
+                         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+                               if (tpnt->next == rpnt->dyn) {
+                                 tpnt->next = tpnt->next->next;
+                                 if (tpnt->next) 
+                                   tpnt->next->prev = tpnt;
+                                 break;
+                               }
+                       free(rpnt->dyn->libname);
+                       free(rpnt->dyn);
+                     }
+               free(rpnt);
+         }
+
+
+       dl_brk = (void (*)()) _dl_debug_addr->r_brk;
+       if( dl_brk != NULL )
+         {
+           _dl_debug_addr->r_state = RT_DELETE;
+           (*dl_brk)();
+           
+           _dl_debug_addr->r_state = RT_CONSISTENT;
+           (*dl_brk)();
+         }
+
+       return 0;
+}
+
+const char * _dlerror()
+{
+       const char * retval;
+       if(!_dl_error_number) return NULL;
+       retval = dl_error_names[_dl_error_number];
+       _dl_error_number = 0;
+       return retval;
+}
+
+/* Generate the correct symbols that we need. */
+#if 1
+#pragma weak dlopen = _dlopen
+#pragma weak dlerror = _dlerror
+#pragma weak dlclose = _dlclose
+#pragma weak dlsym = _dlsym
+#pragma weak dladdr = _dladdr
+#else
+__asm__(".weak dlopen;dlopen=_dlopen");
+__asm__(".weak dlerror;dlerror=_dlerror");
+__asm__(".weak dlclose;dlclose=_dlclose");
+__asm__(".weak dlsym;dlsym=_dlsym");
+__asm__(".weak dladdr;dladdr=_dladdr");
+#endif
+
+/* This is a real hack.  We need access to the dynamic linker, but we
+also need to make it possible to link against this library without any
+unresolved externals.  We provide these weak symbols to make the link
+possible, but at run time the normal symbols are accessed. */
+
+static void foobar()
+{
+       _dl_fdprintf(2,"libdl library not correctly linked\n");
+       _dl_exit(1);
+}
+
+static int foobar1 = (int)foobar; /* Use as pointer */
+
+#if 1
+#pragma weak _dl_find_hash = foobar
+#pragma weak _dl_symbol_tables = foobar1
+#pragma weak _dl_handles = foobar1
+#pragma weak _dl_loaded_modules = foobar1
+#pragma weak _dl_debug_addr = foobar1
+#pragma weak _dl_error_number = foobar1
+#pragma weak _dl_load_shared_library = foobar
+#ifdef USE_CACHE
+#pragma weak _dl_map_cache = foobar
+#pragma weak _dl_unmap_cache = foobar
+#endif
+#pragma weak _dl_malloc_function = foobar1
+#pragma weak _dl_parse_relocation_information = foobar
+#pragma weak _dl_parse_lazy_relocation_information = foobar
+#pragma weak _dl_fdprintf = foobar
+#else
+__asm__(".weak _dl_find_hash; _dl_find_hash = foobar");
+__asm__(".weak _dl_symbol_tables; _dl_symbol_tables = foobar1");
+__asm__(".weak _dl_handles; _dl_handles = foobar1");
+__asm__(".weak _dl_loaded_modules; _dl_loaded_modules = foobar1");
+__asm__(".weak _dl_debug_addr; _dl_debug_addr = foobar1");
+__asm__(".weak _dl_error_number; _dl_error_number = foobar1");
+__asm__(".weak _dl_load_shared_library; _dl_load_shared_library = foobar");
+#ifdef USE_CACHE
+__asm__(".weak _dl_map_cache; _dl_map_cache = foobar");
+__asm__(".weak _dl_unmap_cache; _dl_unmap_cache = foobar");
+#endif
+__asm__(".weak _dl_malloc_function; _dl_malloc_function = foobar1");
+__asm__(".weak _dl_parse_relocation_information; _dl_parse_relocation_information = foobar");
+__asm__(".weak _dl_parse_lazy_relocation_information; _dl_parse_lazy_relocation_information = foobar");
+__asm__(".weak _dl_fdprintf; _dl_fdprintf = foobar");
+#endif
+
+/*
+ * Dump information to stderrr about the current loaded modules
+ */
+static char * type[] = {"Lib","Exe","Int","Mod"};
+
+void _dlinfo()
+{
+       struct elf_resolve * tpnt;
+       struct dyn_elf * rpnt, *hpnt;
+       _dl_fdprintf(2, "List of loaded modules\n");
+       /* First start with a complete list of all of the loaded files. */
+       for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+               _dl_fdprintf(2, "\t%8.8x %8.8x %8.8x %s %d %s\n",
+                       (unsigned)tpnt->loadaddr, (unsigned)tpnt,
+                       (unsigned)tpnt->symbol_scope,
+                       type[tpnt->libtype],
+                       tpnt->usage_count, 
+                       tpnt->libname);
+
+       /* Next dump the module list for the application itself */
+       _dl_fdprintf(2, "\nModules for application (%x):\n",
+               (unsigned)_dl_symbol_tables);
+       for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
+               _dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
+                       rpnt->dyn->libname);
+
+       for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle)
+       {
+               _dl_fdprintf(2, "Modules for handle %x\n", (unsigned)hpnt);
+               for(rpnt = hpnt; rpnt; rpnt = rpnt->next)
+                       _dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
+                               rpnt->dyn->libname);
+       }
+}
+
+int _dladdr(void * __address, Dl_info * __dlip )
+{
+       struct elf_resolve * pelf;
+       struct elf_resolve * rpnt;
+
+#ifdef USE_CACHE
+       _dl_map_cache();
+#endif
+
+       /*
+        * Try and locate the module address is in
+        */
+       pelf = NULL;
+
+#if 0
+       _dl_fdprintf( 2,
+                     "dladdr( 0x%p, 0x%p )\n",
+                     __address, __dlip );
+#endif
+
+       for(rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
+         {
+           struct elf_resolve * tpnt;
+           tpnt = rpnt;
+#if 0
+           _dl_fdprintf( 2,
+                         "Module \"%s\" at 0x%p\n",
+                         tpnt->libname,
+                         tpnt->loadaddr );
+#endif
+           if(   tpnt->loadaddr < (char*)__address
+              && (   pelf == NULL
+                  || pelf->loadaddr < tpnt->loadaddr))
+             pelf = tpnt;
+         }
+
+       if ( ! pelf )
+       {
+         return 0;
+       }
+       
+       /*
+        * Try and locate the symbol of address
+        */
+
+       {
+         char * strtab;
+         struct elf32_sym * symtab;
+         int hn, si;
+         int sf;
+         int sn = 0;
+         void* sa = 0;
+
+         symtab = (struct elf32_sym *) (pelf->dynamic_info[DT_SYMTAB] + 
+                                        pelf->loadaddr);
+         strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
+
+         sf = 0;
+         for(hn = 0; hn < pelf->nbucket; hn++)
+         {
+           for(si = pelf->elf_buckets[hn]; si; si = pelf->chains[si])
+           {
+             void* symbol_addr;
+             symbol_addr = pelf->loadaddr + symtab[si].st_value;
+             if ( symbol_addr <= __address &&
+                  ( !sf || sa < symbol_addr ) )
+             {
+               sa = symbol_addr;
+               sn = si;
+               sf = 1;
+             }
+#if 0
+             _dl_fdprintf( 2,
+                           "Symbol \"%s\" at 0x%p\n",
+                           strtab + symtab[si].st_name,
+                           symbol_addr );
+#endif
+           }
+         }
+
+         if ( sf )
+         {
+           __dlip->dli_fname = pelf->libname;
+           __dlip->dli_fbase = pelf->loadaddr;
+           __dlip->dli_sname = strtab + symtab[sn].st_name;
+           __dlip->dli_saddr = sa;
+         }
+         return 1;
+       }
+}
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
new file mode 100644 (file)
index 0000000..545b674
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * libdl.c
+ * 
+ * Functions required for dlopen et. al.
+ */
+
+#include "dlfcn.h"
+/* #include "link.h" */
+#include <stdlib.h>
+#include <linux/mman.h>
+#include <linux/unistd.h>
+#include "sysdep.h"
+#include "syscall.h"
+#include "hash.h"
+#include "string.h"
+#include "linuxelf.h"
+
+extern int _dl_error_number;
+extern struct r_debug * _dl_debug_addr;
+
+extern void * (*_dl_malloc_function)(size_t size);
+
+static int do_fixup(struct elf_resolve * tpnt, int flag);
+static int do_dlclose(void *, int need_fini);
+
+void * _dlopen(char * filename, int flag);
+const char * _dlerror(void);
+void * _dlsym(void *, char *);
+int _dlclose(void *);
+int _dladdr(void * __address, Dl_info * __dlip );
+
+static const char * dl_error_names[] = {
+       "",
+       "File not found",
+       "Unable to open /dev/zero",
+       "Not an ELF file",
+#if defined (__i386__)
+       "Not i386 binary",
+#elif defined (__sparc__)
+       "Not sparc binary",
+#elif defined (__mc68000__)
+       "Not m68k binary",
+#else
+       "Unrecognized binary type",
+#endif
+       "Not an ELF shared library",
+       "Unable to mmap file",
+       "No dynamic section",
+#ifdef ELF_USES_RELOCA
+       "Unable to process REL relocs",
+#else
+       "Unable to process RELA relocs",
+#endif
+       "Bad handle",
+       "Unable to resolve symbol"
+};
+       
+static void dl_cleanup(void) __attribute__ ((destructor));
+
+static void dl_cleanup(void)
+{
+       struct dyn_elf*         d;
+       
+       for (d = _dl_handles; d; d = d->next_handle)
+               if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI])
+               {
+                       (*((int(*)(void))(d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI])))();
+                       d->dyn->dynamic_info[DT_FINI] = 0;
+               }
+}
+
+void * _dlopen(char * libname, int flag)
+{
+       struct elf_resolve * tpnt, *tfrom;
+       struct dyn_elf * rpnt;
+       struct dyn_elf * dyn_chain;
+       struct dyn_elf * dpnt;
+       static int dl_init = 0;
+       char *  from;
+       void (*dl_brk)(void);
+       int (*dl_elf_init)(void);
+
+       from = __builtin_return_address(0);
+
+       /* Have the dynamic linker use the regular malloc function now */
+       if (!dl_init) {
+               dl_init++;
+               _dl_malloc_function = malloc;
+       }
+
+       /* Cover the trivial case first */
+       if (!libname) return _dl_symbol_tables;
+
+#ifdef USE_CACHE
+       _dl_map_cache();
+#endif
+
+       /*
+        * Try and locate the module we were called from - we
+        * need this so that we get the correct RPATH.  Note that
+        * this is the current behavior under Solaris, but the
+        * ABI+ specifies that we should only use the RPATH from
+        * the application.  Thus this may go away at some time
+        * in the future.
+        */
+       tfrom = NULL;
+       for(dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next)
+         {
+           tpnt = dpnt->dyn;
+           if(   tpnt->loadaddr < from 
+              && (   tfrom == NULL
+                  || tfrom->loadaddr < tpnt->loadaddr))
+             tfrom = tpnt;
+         }
+
+       if(!(tpnt = _dl_load_shared_library(0, tfrom, libname)))
+       {
+#ifdef USE_CACHE
+         _dl_unmap_cache();
+#endif
+         return NULL;
+       }
+
+       tpnt->usage_count++;
+       dyn_chain = rpnt = 
+          (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+       _dl_memset (rpnt, 0, sizeof(*rpnt));
+       rpnt->dyn = tpnt;
+       rpnt->flags = flag;
+       if (!tpnt->symbol_scope) tpnt->symbol_scope = dyn_chain;
+       
+       rpnt->next_handle = _dl_handles;
+       _dl_handles = rpnt;
+
+       /*
+        * OK, we have the requested file in memory.  Now check for
+        * any other requested files that may also be required.
+        */
+         {
+           struct elf_resolve *tcurr;
+           struct elf_resolve * tpnt1;
+           struct dynamic * dpnt;
+           char * lpnt;
+
+           tcurr = tpnt;
+           do{
+             for(dpnt = (struct dynamic *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+               {
+         
+                 if(dpnt->d_tag == DT_NEEDED)
+                   {
+                     lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
+                       dpnt->d_un.d_val;
+                     if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
+                       goto oops;
+
+                     rpnt->next = 
+                        (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+                     _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
+                     rpnt = rpnt->next;
+                     tpnt1->usage_count++;
+                     if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
+                     rpnt->dyn = tpnt1;
+                   };
+               }
+             
+             tcurr = tcurr->next;
+           } while(tcurr);
+         }
+        
+       /*
+        * OK, now attach the entire chain at the end
+        */
+
+       rpnt->next = _dl_symbol_tables;
+
+       if (do_fixup(tpnt, flag)) {
+         _dl_error_number = DL_NO_SYMBOL;
+         goto oops;
+       }
+
+       dl_brk = (void (*)()) _dl_debug_addr->r_brk;
+       if( dl_brk != NULL )
+         {
+           _dl_debug_addr->r_state = RT_ADD;
+           (*dl_brk)();
+           
+           _dl_debug_addr->r_state = RT_CONSISTENT;
+           (*dl_brk)();
+         }
+
+       for(rpnt = dyn_chain; rpnt; rpnt = rpnt->next)
+       {
+               tpnt = rpnt->dyn;
+             /* Apparently crt1 for the application is responsible for handling this.
+              * We only need to run the init/fini for shared libraries
+              */
+             if (tpnt->libtype == elf_executable) continue;
+             if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
+             tpnt->init_flag |= INIT_FUNCS_CALLED;
+      
+             if(tpnt->dynamic_info[DT_INIT]) {
+               dl_elf_init = (int (*)(void)) (tpnt->loadaddr + 
+                                           tpnt->dynamic_info[DT_INIT]);
+               (*dl_elf_init)();
+             }
+       }
+
+#ifdef USE_CACHE
+       _dl_unmap_cache();
+#endif
+       return (void *) dyn_chain;
+
+oops:
+       /* Something went wrong.  Clean up and return NULL. */
+#ifdef USE_CACHE
+       _dl_unmap_cache();
+#endif
+       do_dlclose (dyn_chain, 0);
+       return NULL;
+}
+
+static int do_fixup(struct elf_resolve * tpnt, int flag)
+{
+  int goof = 0;
+  if(tpnt->next) goof += do_fixup(tpnt->next, flag);
+
+  if(tpnt->dynamic_info[DT_REL]) {
+#ifdef ELF_USES_RELOCA
+    goof++;
+#else
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+                                            tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+    if (tpnt->init_flag & RELOCS_DONE) return goof;
+    tpnt->init_flag |= RELOCS_DONE;
+   
+    goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+                                            tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+    goof++;
+#endif
+  }
+  if(tpnt->dynamic_info[DT_JMPREL])
+    {
+      if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
+      tpnt->init_flag |= JMP_RELOCS_DONE;
+      
+      if(flag == RTLD_LAZY)
+       _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+                                             tpnt->dynamic_info[DT_PLTRELSZ], 0);
+      else
+       goof +=  _dl_parse_relocation_information(tpnt,
+                                                 tpnt->dynamic_info[DT_JMPREL],
+                                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
+    };
+  return goof;
+}
+
+void * _dlsym(void * vhandle, char * name)
+{      
+       struct elf_resolve * tpnt, *tfrom;
+       struct dyn_elf * handle;
+       char *  from;
+       struct dyn_elf * rpnt;
+       void *ret;
+
+       handle = (struct dyn_elf *) vhandle;
+
+       /* First of all verify that we have a real handle
+       of some kind.  Return NULL if not a valid handle. */
+
+       if (handle == NULL)
+               handle = _dl_symbol_tables;
+       else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
+               for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
+                       if (rpnt == handle) break;
+               if (!rpnt) {
+                       _dl_error_number = DL_BAD_HANDLE;
+                       return NULL;
+               }
+       }
+       else if (handle == RTLD_NEXT )
+         {
+           /*
+            * Try and locate the module we were called from - we
+            * need this so that we know where to start searching
+            * from.  We never pass RTLD_NEXT down into the actual
+            * dynamic loader itself, as it doesn't know
+            * how to properly treat it.
+            */
+           from = __builtin_return_address(0);
+
+           tfrom = NULL;
+           for(rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
+             {
+               tpnt = rpnt->dyn;
+               if(   tpnt->loadaddr < from 
+                     && (   tfrom == NULL
+                            || tfrom->loadaddr < tpnt->loadaddr))
+                 {
+                   tfrom = tpnt;
+                   handle = rpnt->next;
+                 }
+             }
+         }
+
+       ret = _dl_find_hash(name, handle, 1, NULL, 1);
+
+       /*
+        * Nothing found.
+        */
+       if (!ret)
+               _dl_error_number = DL_NO_SYMBOL;
+       return ret;
+}
+
+int _dlclose(void * vhandle)
+{
+  return do_dlclose(vhandle, 1);
+}
+
+static int do_dlclose(void * vhandle, int need_fini)
+{
+       struct dyn_elf * rpnt, *rpnt1;
+       struct dyn_elf *spnt, *spnt1;
+       struct elf_phdr * ppnt;
+       struct elf_resolve * tpnt;
+       int (*dl_elf_fini)(void);
+       void (*dl_brk)(void);
+       struct dyn_elf * handle;
+       unsigned int end;
+       int i = 0;
+
+       handle = (struct dyn_elf *) vhandle;
+       rpnt1 = NULL;
+       for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
+       {
+               if(rpnt == handle) {
+                       break;
+               }
+               rpnt1 = rpnt;
+       }
+       
+       if (!rpnt) {
+               _dl_error_number = DL_BAD_HANDLE;
+               return 1;
+       }
+
+       /* OK, this is a valid handle - now close out the file.
+        * We check if we need to call fini () on the handle. */
+       spnt = need_fini ? handle : handle->next;
+       for(; spnt; spnt = spnt1)
+       {
+           spnt1 = spnt->next;
+
+           /* We appended the module list to the end - when we get back here, 
+            quit. The access counts were not adjusted to account for being here. */
+           if (spnt == _dl_symbol_tables) break;
+           if(spnt->dyn->usage_count==1 && spnt->dyn->libtype == loaded_file) {
+               tpnt = spnt->dyn;
+               /* Apparently crt1 for the application is responsible for handling this.
+                * We only need to run the init/fini for shared libraries
+                */
+
+               if(tpnt->dynamic_info[DT_FINI]) {
+                   dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
+                                                  tpnt->dynamic_info[DT_FINI]);
+                   (*dl_elf_fini)();
+               }       
+           }
+       }
+       if(rpnt1)
+           rpnt1->next_handle = rpnt->next_handle;
+       else
+           _dl_handles = rpnt->next_handle;
+       
+       /* OK, this is a valid handle - now close out the file */
+       for(rpnt = handle; rpnt; rpnt = rpnt1)
+         {
+               rpnt1 = rpnt->next;
+
+               /* We appended the module list to the end - when we get back here, 
+                  quit. The access counts were not adjusted to account for being here. */
+               if (rpnt == _dl_symbol_tables) break;
+
+               rpnt->dyn->usage_count--;
+               if(rpnt->dyn->usage_count == 0 && rpnt->dyn->libtype == loaded_file)
+               {
+                       tpnt = rpnt->dyn;
+                     /* Apparently crt1 for the application is responsible for handling this.
+                      * We only need to run the init/fini for shared libraries
+                      */
+#if 0
+/* We have to do this above, before we start closing objects.
+Otherwise when the needed symbols for _fini handling are
+resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
+                     if(tpnt->dynamic_info[DT_FINI]) {
+                       dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
+                                                   tpnt->dynamic_info[DT_FINI]);
+                       (*dl_elf_fini)();
+                     } 
+#endif
+                     end = 0;
+                       for(i = 0, ppnt = rpnt->dyn->ppnt; 
+                               i < rpnt->dyn->n_phent; ppnt++, i++) {
+                               if (ppnt->p_type != PT_LOAD) continue;
+                               if (end < ppnt->p_vaddr + ppnt->p_memsz)
+                                       end = ppnt->p_vaddr + ppnt->p_memsz;
+                       }
+                       _dl_munmap (rpnt->dyn->loadaddr, end);
+                       /* Next, remove rpnt->dyn from the loaded_module list */
+                       if (_dl_loaded_modules == rpnt->dyn)
+                       {
+                         _dl_loaded_modules = rpnt->dyn->next;
+                         if (_dl_loaded_modules)
+                           _dl_loaded_modules->prev = 0;
+                       }
+                       else
+                         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+                               if (tpnt->next == rpnt->dyn) {
+                                 tpnt->next = tpnt->next->next;
+                                 if (tpnt->next) 
+                                   tpnt->next->prev = tpnt;
+                                 break;
+                               }
+                       free(rpnt->dyn->libname);
+                       free(rpnt->dyn);
+                     }
+               free(rpnt);
+         }
+
+
+       dl_brk = (void (*)()) _dl_debug_addr->r_brk;
+       if( dl_brk != NULL )
+         {
+           _dl_debug_addr->r_state = RT_DELETE;
+           (*dl_brk)();
+           
+           _dl_debug_addr->r_state = RT_CONSISTENT;
+           (*dl_brk)();
+         }
+
+       return 0;
+}
+
+const char * _dlerror()
+{
+       const char * retval;
+       if(!_dl_error_number) return NULL;
+       retval = dl_error_names[_dl_error_number];
+       _dl_error_number = 0;
+       return retval;
+}
+
+/* Generate the correct symbols that we need. */
+#if 1
+#pragma weak dlopen = _dlopen
+#pragma weak dlerror = _dlerror
+#pragma weak dlclose = _dlclose
+#pragma weak dlsym = _dlsym
+#pragma weak dladdr = _dladdr
+#else
+__asm__(".weak dlopen;dlopen=_dlopen");
+__asm__(".weak dlerror;dlerror=_dlerror");
+__asm__(".weak dlclose;dlclose=_dlclose");
+__asm__(".weak dlsym;dlsym=_dlsym");
+__asm__(".weak dladdr;dladdr=_dladdr");
+#endif
+
+/* This is a real hack.  We need access to the dynamic linker, but we
+also need to make it possible to link against this library without any
+unresolved externals.  We provide these weak symbols to make the link
+possible, but at run time the normal symbols are accessed. */
+
+static void foobar()
+{
+       _dl_fdprintf(2,"libdl library not correctly linked\n");
+       _dl_exit(1);
+}
+
+static int foobar1 = (int)foobar; /* Use as pointer */
+
+#if 1
+#pragma weak _dl_find_hash = foobar
+#pragma weak _dl_symbol_tables = foobar1
+#pragma weak _dl_handles = foobar1
+#pragma weak _dl_loaded_modules = foobar1
+#pragma weak _dl_debug_addr = foobar1
+#pragma weak _dl_error_number = foobar1
+#pragma weak _dl_load_shared_library = foobar
+#ifdef USE_CACHE
+#pragma weak _dl_map_cache = foobar
+#pragma weak _dl_unmap_cache = foobar
+#endif
+#pragma weak _dl_malloc_function = foobar1
+#pragma weak _dl_parse_relocation_information = foobar
+#pragma weak _dl_parse_lazy_relocation_information = foobar
+#pragma weak _dl_fdprintf = foobar
+#else
+__asm__(".weak _dl_find_hash; _dl_find_hash = foobar");
+__asm__(".weak _dl_symbol_tables; _dl_symbol_tables = foobar1");
+__asm__(".weak _dl_handles; _dl_handles = foobar1");
+__asm__(".weak _dl_loaded_modules; _dl_loaded_modules = foobar1");
+__asm__(".weak _dl_debug_addr; _dl_debug_addr = foobar1");
+__asm__(".weak _dl_error_number; _dl_error_number = foobar1");
+__asm__(".weak _dl_load_shared_library; _dl_load_shared_library = foobar");
+#ifdef USE_CACHE
+__asm__(".weak _dl_map_cache; _dl_map_cache = foobar");
+__asm__(".weak _dl_unmap_cache; _dl_unmap_cache = foobar");
+#endif
+__asm__(".weak _dl_malloc_function; _dl_malloc_function = foobar1");
+__asm__(".weak _dl_parse_relocation_information; _dl_parse_relocation_information = foobar");
+__asm__(".weak _dl_parse_lazy_relocation_information; _dl_parse_lazy_relocation_information = foobar");
+__asm__(".weak _dl_fdprintf; _dl_fdprintf = foobar");
+#endif
+
+/*
+ * Dump information to stderrr about the current loaded modules
+ */
+static char * type[] = {"Lib","Exe","Int","Mod"};
+
+void _dlinfo()
+{
+       struct elf_resolve * tpnt;
+       struct dyn_elf * rpnt, *hpnt;
+       _dl_fdprintf(2, "List of loaded modules\n");
+       /* First start with a complete list of all of the loaded files. */
+       for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+               _dl_fdprintf(2, "\t%8.8x %8.8x %8.8x %s %d %s\n",
+                       (unsigned)tpnt->loadaddr, (unsigned)tpnt,
+                       (unsigned)tpnt->symbol_scope,
+                       type[tpnt->libtype],
+                       tpnt->usage_count, 
+                       tpnt->libname);
+
+       /* Next dump the module list for the application itself */
+       _dl_fdprintf(2, "\nModules for application (%x):\n",
+               (unsigned)_dl_symbol_tables);
+       for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
+               _dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
+                       rpnt->dyn->libname);
+
+       for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle)
+       {
+               _dl_fdprintf(2, "Modules for handle %x\n", (unsigned)hpnt);
+               for(rpnt = hpnt; rpnt; rpnt = rpnt->next)
+                       _dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
+                               rpnt->dyn->libname);
+       }
+}
+
+int _dladdr(void * __address, Dl_info * __dlip )
+{
+       struct elf_resolve * pelf;
+       struct elf_resolve * rpnt;
+
+#ifdef USE_CACHE
+       _dl_map_cache();
+#endif
+
+       /*
+        * Try and locate the module address is in
+        */
+       pelf = NULL;
+
+#if 0
+       _dl_fdprintf( 2,
+                     "dladdr( 0x%p, 0x%p )\n",
+                     __address, __dlip );
+#endif
+
+       for(rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
+         {
+           struct elf_resolve * tpnt;
+           tpnt = rpnt;
+#if 0
+           _dl_fdprintf( 2,
+                         "Module \"%s\" at 0x%p\n",
+                         tpnt->libname,
+                         tpnt->loadaddr );
+#endif
+           if(   tpnt->loadaddr < (char*)__address
+              && (   pelf == NULL
+                  || pelf->loadaddr < tpnt->loadaddr))
+             pelf = tpnt;
+         }
+
+       if ( ! pelf )
+       {
+         return 0;
+       }
+       
+       /*
+        * Try and locate the symbol of address
+        */
+
+       {
+         char * strtab;
+         struct elf32_sym * symtab;
+         int hn, si;
+         int sf;
+         int sn = 0;
+         void* sa = 0;
+
+         symtab = (struct elf32_sym *) (pelf->dynamic_info[DT_SYMTAB] + 
+                                        pelf->loadaddr);
+         strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
+
+         sf = 0;
+         for(hn = 0; hn < pelf->nbucket; hn++)
+         {
+           for(si = pelf->elf_buckets[hn]; si; si = pelf->chains[si])
+           {
+             void* symbol_addr;
+             symbol_addr = pelf->loadaddr + symtab[si].st_value;
+             if ( symbol_addr <= __address &&
+                  ( !sf || sa < symbol_addr ) )
+             {
+               sa = symbol_addr;
+               sn = si;
+               sf = 1;
+             }
+#if 0
+             _dl_fdprintf( 2,
+                           "Symbol \"%s\" at 0x%p\n",
+                           strtab + symtab[si].st_name,
+                           symbol_addr );
+#endif
+           }
+         }
+
+         if ( sf )
+         {
+           __dlip->dli_fname = pelf->libname;
+           __dlip->dli_fbase = pelf->loadaddr;
+           __dlip->dli_sname = strtab + symtab[sn].st_name;
+           __dlip->dli_saddr = sa;
+         }
+         return 1;
+       }
+}
diff --git a/ldso/man/Makefile b/ldso/man/Makefile
new file mode 100644 (file)
index 0000000..a701e15
--- /dev/null
@@ -0,0 +1,11 @@
+include ../Config.mk
+
+ALL = #ld.so.info
+
+all:   $(ALL)
+
+ld.so.info: ld.so.texi
+       makeinfo $<
+
+clean:
+       rm -f $(ALL) *~
diff --git a/ldso/man/dlopen.3 b/ldso/man/dlopen.3
new file mode 100644 (file)
index 0000000..8d1e09e
--- /dev/null
@@ -0,0 +1,218 @@
+.\" -*- nroff -*-
+.\" Copyright 1995 Yggdrasil Computing, Incorporated.
+.\" written by Adam J. Richter (adam@yggdrasil.com),
+.\" with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com).
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU 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 General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual 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 General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, write to the Free
+.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+.\" USA.
+.\"
+.TH DLOPEN 3 "16 May 1995" "Linux" "Linux Programmer's Manual"
+.SH NAME
+dlclose, dlerror, dlopen, dlsym \- Programming interface to dynamic linking loader.
+.SH SYNOPSIS
+.B #include <dlfcn.h>
+.sp
+.BI "void *dlopen (const char *" "filename" ", int " flag ");
+.br
+.BI "const char *dlerror(void);"
+.br
+.BI "void *dlsym(void *"handle ", char *"symbol ");"
+.br
+.BI "int dladdr(void *"address ", Dl_info *"dlip ");"
+.br
+.BI "int dlclose (void *"handle ");
+.sp
+Special symbols:
+.BR "_init" ", " "_fini" ". "
+.SH DESCRIPTION
+.B dlopen
+loads a dynamic library from the file named by the null terminated
+string
+.I filename
+and returns an opaque "handle" for the dynamic library.
+If
+.I filename
+is not an absolute path (i.e., it does not begin with a "/"), then the
+file is searched for in the following locations:
+.RS
+.PP
+A colon-separated list of directories in the user's
+\fBLD_LIBRARY\fP path environment variable.
+.PP
+The list of libraries specified in \fI/etc/ld.so.cache\fP.
+.PP
+\fI/usr/lib\fP, followed by \fI/lib\fP.
+.RE
+.PP
+If
+.I filename
+is a NULL pointer, then the returned handle is for the main program.
+.PP
+External references in the library are resolved using the libraries
+in that library's dependency list and any other libraries previously
+opened with the 
+.B RTLD_GLOBAL
+flag.
+If the executable was linked
+with the flag "-rdynamic", then the global symbols in the executable
+will also be used to resolve references in a dynamically loaded
+library.
+.PP
+.I flag
+must be either
+.BR RTLD_LAZY ,
+meaning resolve undefined symbols as code from the dynamic library is
+executed, or
+.BR RTLD_NOW ,
+meaning resolve all undefined symbols before
+.B dlopen
+returns, and fail if this cannot be done.
+Optionally,
+.B RTLD_GLOBAL
+may be or'ed with
+.IR flag,
+in which case the external symbols defined in the library will be
+made available to subsequently loaded libraries.
+.PP
+If the library exports a routine named
+.BR _init ,
+then that code is executed before dlopen returns.
+If the same library is loaded twice with
+.BR dlopen() ,
+the same file handle is returned.  The dl library maintains link
+counts for dynamic file handles, so a dynamic library is not
+deallocated until
+.B dlclose
+has been called on it as many times as
+.B dlopen
+has succeeded on it.
+.PP
+If
+.B dlopen
+fails for any reason, it returns NULL.
+A human readable string describing the most recent error that occurred
+from any of the dl routines (dlopen, dlsym or dlclose) can be
+extracted with
+.BR dlerror() .
+.B dlerror
+returns NULL if no errors have occurred since initialization or since
+it was last called.  (Calling
+.B dlerror()
+twice consecutively, will always result in the second call returning
+NULL.)
+
+.B dlsym
+takes a "handle" of a dynamic library returned by dlopen and the null
+terminated symbol name, returning the address where that symbol is
+loaded.  If the symbol is not found,
+.B dlsym
+returns NULL; however, the correct way to test for an error from
+.B dlsym
+is to save the result of
+.B dlerror
+into a variable, and then check if saved value is not NULL.
+This is because the value of the symbol could actually be NULL.
+It is also necessary to save the results of
+.B dlerror
+into a variable because if
+.B dlerror
+is called again, it will return NULL.
+.PP
+.B dladdr
+returns information about the shared library containing the memory 
+location specified by
+.IR address .
+.B dladdr
+returns zero on success and non-zero on error.
+.PP
+.B dlclose
+decrements the reference count on the dynamic library handle
+.IR handle .
+If the reference count drops to zero and no other loaded libraries use
+symbols in it, then the dynamic library is unloaded.  If the dynamic
+library exports a routine named
+.BR _fini ,
+then that routine is called just before the library is unloaded.
+.SH EXAMPLES
+.B Load the math library, and print the cosine of 2.0:
+.RS
+.nf
+.if t .ft CW
+#include <dlfcn.h>
+
+int main(int argc, char **argv) {
+    void *handle = dlopen ("/lib/libm.so", RTLD_LAZY);
+    double (*cosine)(double) = dlsym(handle, "cos");
+    printf ("%f\\n", (*cosine)(2.0));
+    dlclose(handle);
+}
+.if t .ft P
+.fi
+.PP
+If this program were in a file named "foo.c", you would build the program
+with the following command:
+.RS
+.LP
+gcc -rdynamic -o foo foo.c -ldl
+.RE
+.RE
+.LP
+.B Do the same thing, but check for errors at every step:
+.RS
+.nf
+.if t .ft CW
+#include <stdio.h>
+#include <dlfcn.h>
+
+int main(int argc, char **argv) {
+    void *handle;
+    double (*cosine)(double);
+    char *error;
+
+    handle = dlopen ("/lib/libm.so", RTLD_LAZY);
+    if (!handle) {
+        fputs (dlerror(), stderr);
+        exit(1);
+    }
+
+    cosine = dlsym(handle, "cos");
+    if ((error = dlerror()) != NULL)  {
+        fputs(error, stderr);
+        exit(1);
+    }
+
+    printf ("%f\\n", (*cosine)(2.0));
+    dlclose(handle);
+}
+.if t .ft P
+.fi
+.RE
+.SH ACKNOWLEDGEMENTS
+The dlopen interface standard comes from Solaris.
+The Linux dlopen implementation was primarily written by
+Eric Youngdale with help from Mitch D'Souza, David Engel,
+Hongjiu Lu, Andreas Schwab and others.
+The manual page was written by Adam Richter.
+.SH SEE ALSO
+.BR ld(1) ,
+.BR ld.so(8) ,
+.BR ldconfig(8) ,
+.BR ldd(1) ,
+.BR ld.so.info .
diff --git a/ldso/man/ld.so.8 b/ldso/man/ld.so.8
new file mode 100644 (file)
index 0000000..59ec853
--- /dev/null
@@ -0,0 +1,113 @@
+.TH ld.so 8 "14 March 1998"
+.SH NAME
+ld.so/ld-linux.so \- dynamic linker/loader
+.SH DESCRIPTION
+.B ld.so
+loads the shared libraries needed by a program, prepares the program
+to run, and then runs it.
+Unless explicitly specified via the
+.B \-static
+option to
+.B ld
+during compilation, all Linux programs are incomplete and require 
+further linking at run time.
+.PP
+The necessary shared libraries needed by the program are searched for 
+in the following order
+.IP o
+Using the environment variable
+.B LD_LIBRARY_PATH
+.RB ( LD_AOUT_LIBRARY_PATH
+for a.out programs).
+Except if the executable is a setuid/setgid binary, in which case it
+is ignored.
+.IP o
+From the cache file
+.BR /etc/ld.so.cache
+which contains a compiled list of candidate libraries previously found
+in the augmented library path.
+.IP o
+In the default path
+.BR /usr/lib ,
+and then
+.BR /lib .
+.SH ENVIRONMENT
+.TP
+.B LD_LIBRARY_PATH
+A colon-separated list of directories in which to search for
+ELF libraries at execution-time.
+Similar to the 
+.B PATH
+environment variable.
+.TP
+.B LD_PRELOAD
+A whitespace-separated list of additional, user-specified, ELF shared 
+libraries to be loaded before all others.
+This can be used to selectively override functions in other shared libraries.
+For setuid/setgid ELF binaries, only libraries in the standard search
+directories that are also setgid will be loaded.
+.TP
+.B LD_TRACE_LOADED_OBJECTS
+If present, causes the program to list its dynamic library dependencies,
+as if run by ldd, instead of running normally.
+.TP
+.B LD_BIND_NOW
+If present, causes the dynamic linker to resolve all symbols at program
+startup instead of when they are first referenced.
+.TP
+.B LD_AOUT_LIBRARY_PATH
+A colon-separated list of directories in which to search for
+a.out libraries at execution-time.
+Similar to the 
+.B PATH
+environment variable.
+.TP
+.B LD_AOUT_PRELOAD
+The name of an additional, user-specified, a.out shared library to be loaded 
+after all others.
+This can be used to selectively override functions in other shared libraries.
+.TP
+.B LD_NOWARN
+Suppress warnings about a.out libraries with incompatible minor 
+version numbers.
+.TP
+.B LD_KEEPDIR
+Don't ignore the directory in the names of a.out libraries to be loaded.
+Use of this option is strongly discouraged.
+.SH FILES
+.PD 0
+.TP 20
+.B /lib/ld.so
+a.out dynamic linker/loader
+.TP 20
+.B /lib/ld-linux.so.*
+ELF dynamic linker/loader
+.TP
+.B /etc/ld.so.cache
+File containing a compiled list of directories in which to search for
+libraries and an ordered list of candidate libraries.
+.TP
+.B /etc/ld.so.preload
+File containing a whitespace separated list of ELF shared libraries to
+be loaded before the program.
+libraries and an ordered list of candidate libraries.
+.TP
+.B lib*.so*
+shared libraries
+.PD
+.SH SEE ALSO
+.BR ldd (1),
+.BR ldconfig (8).
+.SH BUGS
+.LP
+Currently
+.B ld.so
+has no means of unloading and searching for compatible or newer version of
+libraries.
+.PP
+.B ld.so
+functionality is only available for executables compiled using libc version
+4.4.3 or greater.
+.SH AUTHORS
+David Engel, Eric Youngdale, Peter MacDonald, Hongjiu Lu, Linus
+Torvalds, Lars Wirzenius and Mitch D'Souza (not necessarily in that order).
diff --git a/ldso/man/ld.so.texi b/ldso/man/ld.so.texi
new file mode 100644 (file)
index 0000000..4e5fb84
--- /dev/null
@@ -0,0 +1,411 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename ld.so.info
+@settitle ld.so : Dynamic-Link Library support
+@c %**end of header
+
+@ifinfo
+This file documents the dynamic-link support libraries and utilities for the
+Linux OS, version 1.8.1.
+
+Copyright 1996 Michael Deutschmann
+
+This document is subject to the GNU General Public License as published by 
+the Free Software foundation, version 2 or later (your choice).
+
+Note: The software described in this document is under a different copyright
+and license.
+
+@end ifinfo
+
+@titlepage 
+@title ld.so
+@subtitle Dynamic Link library support for the Linux OS.
+@author David Engel
+@author Eric Youngdale
+@author Peter Macdonald 
+@author Hongjiu Lu 
+@author Mitch D'Souza
+@author Michael Deutschmann (this documentation)
+
+@page
+Copyright @copyright{} 1996 Michael Deutschmann
+
+This document is subject to the GNU General Public License as published by 
+the Free Software foundation, version 2 or later (your choice).
+
+Note: The software described in this document is under a different copyright
+and license.
+@end titlepage
+
+@ifinfo
+@node Top
+@top
+
+The @code{ld.so} module provides dynamic linked library support in Linux.
+This file documents @code{ld.so} and its companion software.
+
+@menu
+* intro::      Introduction
+
+* ld.so::      The dynamic linker core program
+* ldd::                A utility to print out dependencies
+* ldconfig::   A utility to maintain the cache and symlinks
+* libdl::      Manual dynamic linking library
+@end menu
+
+@end ifinfo
+
+@node intro
+@unnumbered Introduction
+
+The @code{ld.so} suite contains special files and utilities needed for linux
+to handle @dfn{dynamic libraries}.
+
+Ordinary static libraries (@file{lib*.a} files) are included into executables
+that use their functions. A file that only uses static libraries needs less
+intelligence to load, but takes up more space. If many executables use the
+same library, there can be much wastage of storage space, since multiple
+copies of the library functions are scattered across the executables.
+However, static libraries are easier to make.
+
+Dynamic libraries (@file{lib*.so*} files) are not copied into executables ---
+the executable is written in such a way that it will automatically load the
+libraries. In linux, the executable will first load the special library 
+@code{ld.so} or @code{ld-linux.so}, which contains the intelligence
+to load further dynamic libraries. Since multiple files end up getting
+executable data from the same file, dynamic libraries are also known as
+shared libraries.
+
+Linux executables come in two flavors, @sc{elf} and a.out.
+
+a.out is the original executable format used by Linux. It has somewhat less 
+overhead than @sc{elf}. However creating shared libraries for a.out is
+@emph{very} involved, and each a.out shared library must be explicitly 
+registered.
+@sc{elf} is a more recent format, which supports a much simpler method of
+creating libraries. @sc{elf} libraries may also be linked manually
+(@pxref{libdl}).
+
+Since many library authors prefer @sc{elf} and no longer release shared a.out 
+libraries, a.out is moribund on Linux. This version of the @code{ld.so} can
+be compiled to support only @sc{elf}, or to support both formats. (The last
+release of ld.so to support a.out alone was 1.8.0.)
+
+@node ld.so
+@chapter @code{ld.so}: Dynamic linker core
+
+@code{ld.so} works behind the scenes to handle dynamic libraries in Linux.
+Users will almost never have to deal with it directly, but in special cases
+one can send instructions to it through environment variables. Also, if
+something is wrong with your libraries (usually an incorrect version) ld.so
+will give error messages.
+
+Actually @code{ld.so} is the a.out linker. The new @sc{elf} executables are
+handled by a related program @code{ld-linux.so}.
+
+@menu
+* files::      Configuration files used by the suite
+* environment::        Environment settings that tweak @code{ld.so}
+* errors::     Complaints @code{ld.so} might make
+@end menu
+
+@node files
+@section Configuration Files
+
+@table @file
+@item /etc/ld.so.cache
+A file created by @code{ldconfig} and used to speed linking. It's structure
+is private to the suite.
+
+@item /etc/ld.so.conf
+A simple list of directories to scan for libraries, in addition to
+@file{/usr/lib} and @file{/lib}, which are hardwired. It may contain
+comments started with a @samp{#}.
+
+@item /etc/ld.so.preload
+A list of libraries to preload. This allows preloading libraries for
+setuid/setgid executables securely. It may contain comments. 
+@end table
+
+@node environment
+@section Environment Variables
+
+@table @code
+@item LD_AOUT_LIBRARY_PATH
+@itemx LD_LIBRARY_PATH
+These variables supply a library path for finding dynamic libraries, in the
+standard colon seperated format. These variables are ignored when executing 
+setuid/setgid programs, because otherwise they would be a security hazard. 
+@code{ld.so} will use @code{LD_AOUT_LIBRARY_PATH} and @code{ld-linux.so} will 
+use @code{LD_LIBRARY_PATH}.
+
+@item LD_AOUT_PRELOAD
+@itemx LD_PRELOAD
+These variables allow an extra library not specified in the executable to be
+loaded. Generally this is only useful if you want to override a function. 
+These are also ignored when running setuid/setgid executables. @code{ld.so} 
+will use @code{LD_AOUT_PRELOAD} and @code{ld-linux.so} will use 
+@code{LD_PRELOAD}.
+
+@item LD_NOWARN
+If non-empty, errors about incompatible minor revisions are suppressed.
+
+@item LD_KEEPDIR
+If non-empty, allow executables to specify absolute library names. This
+option is deprecated.
+@c FIXME:
+@c The following are things I noticed in the ld-linux.so source.
+@c I don't really understand 'em. Could someone help me?
+@c
+@c @item LD_BIND_NOW
+@c This option is used by the @code{ld-linux.so} only. I don't know 
+@c what it does. (I suspect, looking at the code, that it specifies
+@c "RTLD_NOW" rather than "RTLD_LAZY" mode for the shared libraries.)
+@c 
+@c @item LD_TRACE_LOADED_OBJECTS
+@c @itemx LD_WARN
+@c These seem to have something to do with the communication between the
+@c @code{ld-linux.so} and @code{ldd}. I don't know more.
+@end table
+
+@node errors
+@section Errors
+
+@table @samp
+@item Can't find library @var{library}
+The executable required a dynamically linked library that ld.so cannot find.
+Your symbolic links may be not set right, or you may have not installed a 
+library needed by the program.
+
+@item Can't load library @var{library}
+The library is corrupt. 
+
+@item Incompatible library @var{library}
+@itemx   Require major version @var{x} and found @var{y}
+Your version of the library is incompatible with the executable. Recompiling
+the executable, or upgrading the library will fix the problem.
+
+@item using incompatible library @var{library}
+@itemx   Desire minor version >= @var{x} and found @var{y}.
+Your version of the library is older than that expected by the executable,
+but not so old that the library interface has radically changed, so the
+linker will attempt to run anyway. There is a chance that it will work, but 
+you should upgrade the library or recompile the software. The environment 
+variable @code{LD_NOWARN} can be used to supress this message.
+
+@item too many directories in library path
+The linker only supports up to 32 library directories. You have too many.
+
+@item dynamic linker error in @var{blah}
+The linker is having trouble handling a binary - it is probably corrupt.
+
+@item can't map cache file @var{cache-file}
+@itemx cache file @var{cache-file} @var{blah}
+The linker cache file (generally @file{/etc/ld.so.cache}) is corrupt or
+non-existent. These errors can be ignored, and can be prevented by 
+regenerating the cache file with @code{ldconfig}.
+@end table
+
+@node ldd
+@chapter @code{ldd}: Dependency scanner
+
+@code{ldd} is a utility that prints out the dynamic libraries that an
+executable is linked to. 
+
+Actually @code{ldd} works by signalling ld.so to print the dependencies. 
+For a.out executables this is done by starting the executable with 
+@code{argc} equal to 0. The linker detects this and prints the dependencies. 
+(This can cause problems with @emph{very} old binaries, which would run as 
+normal only with an inappropriate @code{argc}.)
+
+For @sc{elf} executables, special environment variables are used to tell the
+linker to print the dependencies.
+
+@code{ldd} has a few options:
+
+@table @samp
+@item -v
+Print the version number of @code{ldd} itself
+
+@item -V
+Print the version number of the dynamic linker
+
+@item -d
+Report missing functions. This is only supported for @sc{elf} executables.
+
+@item -r
+Report missing objects. This is also only available for @sc{elf}
+executables.
+@end table
+
+@node ldconfig
+@chapter @code{ldconfig}: Setup program 
+
+This utility is used by the system administrator to automatically set up
+symbolic links needed by the libraries, and also to set up the cache file.
+
+@code{ldconfig} is run after new dynamic libraries are installed, and if the 
+cache file or links are damaged. It is also run when upgrading the
+@code{ld.so} suite itself.
+
+The @file{/lib} and @file{/usr/lib} directories, and any listed in the file 
+@file{/etc/ld.so.conf} are scanned by default unless @samp{-n} is used.
+Additional directories may be specified on the command line.
+
+It has the following options:
+
+@table @samp
+@item -D
+Enter debug mode. Implies @samp{-N} and @samp{-X}.
+
+@item -v
+Verbose. Print out links created and directories scanned.
+
+@item -n 
+Check directories specified on the commandline @emph{only}.
+
+@item -N
+Do not regenerate the cache.
+
+@item -X
+Do not rebuild symbolic links.
+
+@item -l
+Set up symbolic links for only libraries presented on the command line.
+
+@item -p
+Print out the library pathnames in the cache file (@file{/etc/ld.so.cache})
+@end table
+
+@node libdl
+@chapter User dynamic linking library
+
+The @code{ld.so} package includes a small library of functions
+(@code{libdl}) to allow manual dynamic linking. Normally programs are linked 
+so that dynamic functions and objects are automagically available. These 
+functions allow one to manually load and access a symbol from a library. 
+They are only available for @sc{elf} executables.
+
+@menu
+* using libdl::        General points
+* functions::  How to use the functions
+* example::    A sample program
+@end menu
+
+@node using libdl
+@section Overview
+
+To access this library, add the flag @samp{-ldl} to your compile command when
+linking the executable. You also must include the header file
+@code{dlfcn.h}. You may also need the flag @samp{-rdynamic}, which enables
+resolving references in the loaded libraries against your executable.
+
+Generally, you will first use @code{dlopen} to open a library. Then you use
+@code{dlsym} one or more times to access symbols. Finally you use
+@code{dlclose} to close the library.
+
+These facilities are most useful for language interpreters that provide
+access to external libraries. Without @code{libdl}, it would be neccessary
+to link the interpreter executable with any and all external libraries
+needed by the programs it runs. With @code{libdl}, the interpreter only 
+needs to be linked with the libraries it uses itself, and can dynamically 
+load in additional ones if programs need it.
+
+@node functions
+@section Functions
+
+@deftypefun void *dlopen ( const char @var{filename}, int @var{flags} )
+
+This function opens the dynamic library specified by @var{filename}
+and returns an abstract handle, which can be used in subsequent calls to 
+@code{dlsym}. The function will respect the @code{LD_ELF_LIBRARY_PATH} and
+@code{LD_LIBRARY_PATH} environment variables.
+
+@end deftypefun
+
+The following flags can be used with @code{dlopen}:
+
+@deftypevr Macro int RTLD_LAZY
+Resolve symbols in the library as they are needed.
+@end deftypevr
+
+@deftypevr Macro int RTLD_NOW
+Resolve all symbols in the library before returning, and fail if not all can
+be resolved. This is mutually exclusive with @code{RTLD_LAZY}.
+@end deftypevr
+
+@deftypevr Macro int RTLD_GLOBAL
+Make symbols in this library available for resolving symbols in other
+libraries loaded with @code{dlopen}.
+@end deftypevr
+
+@deftypefun int dlclose ( void *@var{handle} )
+
+This function releases a library handle.
+
+Note that if a library opened twice, the handle will be the same. However,
+a reference count is used, so you should still close the library as many 
+times as you open it.
+
+@end deftypefun
+
+@deftypefun void *dlsym (void *@var{handle},char *@var{symbol-name})
+
+This function looks up the name @var{symbol-name} in the library and returns
+it in the void pointer.
+
+If there is an error, a null pointer will be returned. However, it is
+possible for a valid name in the library to have a null value, so
+@code{dlerror} should be used to check if there was an error.
+
+@end deftypefun
+
+@deftypefun {libdl function} {const char} *dlerror( void )
+
+This function is used to read the error state. It returns a human-readable
+string describing the last error, or null, meaning no error.
+
+The function resets the error value each time it is called, so the result
+should be copied into a variable. If the function is called more than once
+after an error, the second and subsequent calls will return null.
+
+@end deftypefun
+
+@node example
+@section Example program
+
+Here is an example program that prints the cosine of two by manually linking
+to the math library:
+@example
+@c The following was snarfed verbatim from the dlopen.3 man file.
+#include <stdio.h>
+#include <dlfcn.h>
+
+int main(int argc, char **argv) @{
+    void *handle;
+    double (*cosine)(double);
+    char *error;
+
+    handle = dlopen ("/lib/libm.so", RTLD_LAZY);
+    if (!handle) @{
+        fputs (dlerror(), stderr);
+        exit(1);
+    @}
+
+    cosine = dlsym(handle, "cos");
+    if ((error = dlerror()) != NULL)  @{
+        fputs(error, stderr);
+        exit(1);
+    @}
+
+    printf ("%f\\n", (*cosine)(2.0));
+    dlclose(handle);
+@}
+@end example
+
+@contents
+
+@bye
diff --git a/ldso/man/ldconfig.8 b/ldso/man/ldconfig.8
new file mode 100644 (file)
index 0000000..8228529
--- /dev/null
@@ -0,0 +1,189 @@
+.TH ldconfig 8 "14 March 1998"
+.SH NAME
+ldconfig \- determine run-time link bindings
+.SH SYNOPSIS
+ldconfig
+.RB [ \-DvqnNX ]
+.RB [ \-f\ conf ]
+.RB [ \-C\ cache ]
+.RB [ \-r\ root ]
+.IR directory \ ...
+.PD 0
+.PP
+.PD
+ldconfig
+.B \-l
+.RB [ \-Dvq ]
+.IR library \ ...
+.PD 0
+.PP
+.PD
+ldconfig
+.B \-p
+.SH DESCRIPTION
+.B ldconfig
+creates the necessary links and cache (for use by the run-time linker,
+.IR ld.so )
+to the most recent shared libraries found in the directories specified
+on the command line, in the file
+.IR /etc/ld.so.conf ,
+and in the trusted directories
+.RI ( /usr/lib
+and
+.IR /lib ).
+.B ldconfig
+checks the header and file names of the libraries it encounters when
+determining which versions should have their links updated.
+.B ldconfig
+ignores symbolic links when scanning for libraries. 
+.PP
+.B ldconfig
+will attempt to deduce the type of ELF libs (ie. libc5 or libc6/glibc)
+based on what C libs if any the library was linked against, therefore when
+making dynamic libraries, it is wise to explicitly link against libc (use -lc).
+.PP
+Some existing libs do not contain enough information to allow the deduction of 
+their type, therefore the 
+.IR /etc/ld.so.conf 
+file format allows the specification of an expected type.  This is 
+.B only
+used for those ELF libs which we can not work out. The format 
+is like this "dirname=TYPE", where type can be libc4, libc5 or libc6.
+(This syntax also works on the command line).  Spaces are 
+.B not 
+allowed.  Also see the 
+.B -p 
+option.
+.PP 
+Directory names containing an
+.B = are no longer legal
+unless they also have an expected type specifier.
+.PP
+.B ldconfig
+should normally be run by the super-user as it may require write 
+permission on some root owned directories and files.
+It is normally run automatically at bootup, from /etc/rc, or manually
+whenever new DLL's are installed.
+.SH OPTIONS
+.TP
+.B \-D
+Debug mode.
+Implies
+.B \-N
+and
+.BR \-X .
+.TP
+.B \-v
+Verbose mode.
+Print current version number, the name of each directory as it
+is scanned and any links that are created.
+Overrides quiet mode.
+.TP
+.B \-q
+Quiet mode.
+Don't print warnings.
+.TP
+.B \-n
+Only process directories specified on the command line.
+Don't process the trusted directories
+.RI ( /usr/lib
+and
+.IR /lib )
+nor those specified in
+.IR /etc/ld.so.conf .
+Implies
+.BR \-N .
+.TP
+.B \-N
+Don't rebuild the cache.
+Unless
+.B \-X
+is also specified, links are still updated.
+.TP
+.B \-X
+Don't update links.
+Unless
+.B \-N
+is also specified, the cache is still rebuilt.
+.TP
+.B \-f conf
+Use
+.B conf
+instead of
+.IR /etc/ld.so.conf .
+.TP
+.B \-C cache
+Use
+.B cache
+instead of
+.IR /etc/ld.so.cache .
+.TP
+.B \-r root
+Change to and use
+.B root
+as the root directory.
+.TP
+.B \-l
+Library mode.
+Manually link individual libraries.
+Intended for use by experts only.
+.TP
+.B \-p
+Print the lists of directories and candidate libraries stored in
+the current cache.
+.SH EXAMPLES
+In the bootup file
+.I /etc/rc
+having the line
+.RS
+
+/sbin/ldconfig -v
+
+.RE
+will set up the correct links for the shared binaries and rebuild
+the cache.
+.TP
+On the command line
+.RS
+
+# /sbin/ldconfig -n /lib
+
+.RE
+as root after the installation of a new DLL, will properly update the
+shared library symbolic links in /lib.
+
+.SH FILES
+.PD 0
+.TP 20
+.B /lib/ld.so
+execution time linker/loader
+.TP 20
+.B /etc/ld.so.conf
+File containing a list of colon, space, tab, newline, or comma spearated
+directories in which to search for libraries.
+.TP 20
+.B /etc/ld.so.cache
+File containing an ordered list of libraries found in the directories
+specified in
+.BR /etc/ld.so.conf .
+.TP
+.B lib*.so.version
+shared libraries
+.PD
+.SH SEE ALSO
+.BR ldd (1),
+.BR ld.so (8).
+.SH BUGS
+.LP
+.BR ldconfig 's
+functionality, in conjunction with
+.BR ld.so ,
+is only available for executables compiled using libc version 4.4.3 or greater.
+.PP
+.BR ldconfig ,
+being a user process, must be run manually and has no means of dynamically
+determining and relinking shared libraries for use by
+.BR ld.so
+when a new DLL is installed.
+.SH AUTHORS
+David Engel and Mitch D'Souza.
diff --git a/ldso/man/ldd.1 b/ldso/man/ldd.1
new file mode 100644 (file)
index 0000000..20c5578
--- /dev/null
@@ -0,0 +1,59 @@
+.\" Copyright 1995-2000 David Engel (david@ods.com)
+.\" Copyright 1995 Rickard E. Faith (faith@cs.unc.edu)
+.\" Most of this was copied from the README file.  Do not restrict distribution.
+.\" May be distributed under the GNU General Public License
+.TH LDD 1 "14 March 1998"
+.SH NAME
+ldd \- print shared library dependencies
+.SH SYNOPSIS
+.B ldd
+.RB [ \-vVdr ]
+program|library ...
+.SH DESCRIPTION
+.B ldd
+prints the shared libraries required by each program or shared library
+specified on the command line.
+If a shared library name does not contain a '/',
+.B ldd
+attempts to locate the library in the standard locations.
+To run
+.B ldd
+on a shared library in the current directory, a "./" must be prepended
+to its name.
+.SH OPTIONS
+.TP
+.B \-v
+Print the version number of
+.BR ldd .
+.TP
+.B \-V
+Print the version number of the dynamic linker,
+.BR ld.so .
+.TP
+.B \-d
+Perform relocations and report any missing functions (ELF only).
+.TP
+.B \-r
+Perform relocations for both data objects and functions, and
+report any missing objects (ELF only).
+.SH BUGS
+.B ldd
+does not work very well on libc.so.5 itself.
+.PP
+.B ldd
+does not work on a.out shared libraries.
+.PP
+.B ldd
+does not work with some extremely old a.out programs which were 
+built before
+.B ldd
+support was added to the compiler releases.
+If you use
+.B ldd
+on one of these programs, the program will attempt to run with argc = 0 and
+the results will be unpredictable.
+.SH AUTHOR
+David Engel.
+.SH SEE ALSO
+.BR ldconfig (8),
+.BR ld.so (8).
diff --git a/ldso/util/Makefile b/ldso/util/Makefile
new file mode 100644 (file)
index 0000000..18e8794
--- /dev/null
@@ -0,0 +1,38 @@
+TOPDIR=../../
+include $(TOPDIR)Rules.mak
+include ../Config.mk
+
+CFLAGS += -DLDSO_ADDR="0x62f00020" # needed by ldd.o
+CFLAGS += -I./ -I../../include/
+LDFLAGS += -nostdlib ../../libc.a ../../crt0.o $(GCCINCDIR)/../libgcc.a
+
+ALL    = ldconfig ldd # lddstub
+
+all:   $(ALL)
+
+CSRC= readelf.c ldconfig.c ldd.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+OBJS=$(COBJS)
+
+$(COBJS): %.o : %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+       $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+readelf.o: readelf.c readelf2.c
+
+ldconfig: ldconfig.o readelf.o
+       $(CC) -static $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+ldd:   ldd.o readelf.o
+       $(CC) -static $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+#ifeq ($(DEBUG),true)
+#STUBFLAGS = -Wl,-dynamic-linker,../d-link/ld-linux.so
+#endif
+
+#lddstub: lddstub.o
+#      $(CC) $(CFLAGS) $(LDFLAGS) $(STUBFLAGS) $^ -o $@
+
+clean:
+       rm -f $(ALL) *.o *~ core
+
diff --git a/ldso/util/ldconfig.c b/ldso/util/ldconfig.c
new file mode 100644 (file)
index 0000000..2b3d50c
--- /dev/null
@@ -0,0 +1,837 @@
+/*
+ * ldconfig - update shared library symlinks
+ *
+ * usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...
+ *        ldconfig -l [-Dv] lib ...
+ *        ldconfig -p
+ *        -D: debug mode, don't update links
+ *        -v: verbose mode, print things as we go
+ *        -q: quiet mode, don't print warnings
+ *        -n: don't process standard directories
+ *        -N: don't update the library cache
+ *        -X: don't update the library links
+ *        -l: library mode, manually link libraries
+ *        -p: print the current library cache
+ *        -f conf: use conf instead of /etc/ld.so.conf
+ *        -C cache: use cache instead of /etc/ld.so.cache
+ *        -r root: first, do a chroot to the indicated directory
+ *        dir ...: directories to process
+ *        lib ...: libraries to link
+ *
+ * Copyright 1994-2000 David Engel and Mitch D'Souza
+ *
+ * This program may be used for any purpose as long as this
+ * copyright notice is kept.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <a.out.h>
+#include <link.h>
+#include <elf.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "../config.h"
+#include "readelf.h"
+
+#ifdef __GNUC__
+void warn(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+#endif
+
+char *___strtok = NULL;
+
+/* For SunOS */
+#ifndef PATH_MAX
+#include <limits.h>
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+/* For SunOS */
+#ifndef N_MAGIC
+#define N_MAGIC(exec) ((exec).a_magic & 0xffff)
+#endif
+
+#define EXIT_OK    0
+#define EXIT_FATAL 128
+
+char *prog = NULL;
+int debug = 0;                 /* debug mode */
+int verbose = 0;               /* verbose mode */
+int libmode = 0;               /* library mode */
+int nocache = 0;               /* don't build cache */
+int nolinks = 0;               /* don't update links */
+
+char *conffile = LDSO_CONF;    /* default conf file */
+char *cachefile = LDSO_CACHE;  /* default cache file */
+void cache_print(void);
+void cache_dolib(const char *dir, const char *so, int libtype);
+void cache_write(void);
+
+void warn(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (verbose < 0)
+        return;
+
+    fflush(stdout);    /* don't mix output and error messages */
+    fprintf(stderr, "%s: warning: ", prog);
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\n");
+
+    return;
+}
+
+void error(const char *fmt, ...)
+{
+    va_list ap;
+
+    fflush(stdout);    /* don't mix output and error messages */
+    fprintf(stderr, "%s: ", prog);
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\n");
+
+    exit(EXIT_FATAL);
+}
+
+void *xmalloc(size_t size)
+{
+    void *ptr;
+    if ((ptr = malloc(size)) == NULL)
+       error("out of memory");
+    return ptr;
+}
+
+char *xstrdup(const char *str)
+{
+    char *ptr;
+    if ((ptr = strdup(str)) == NULL)
+       error("out of memory");
+    return ptr;
+}
+
+/* If shared library, return a malloced copy of the soname and set the
+   type, else return NULL.
+
+   expected_type should be either LIB_ANY or one of the following:-
+   LIB_DLL
+   LIB_ELF
+   LIB_ELF_LIBC5
+   LIB_ELF_LIBC6
+
+   If the lib is ELF and we can not deduce the type the type will
+   be set based on expected_type.
+
+   If the expected, actual/deduced types missmatch we display a warning
+   and use the actual/deduced type.
+*/
+char *is_shlib(const char *dir, const char *name, int *type,
+       int *islink, int expected_type)
+{
+    char *good = NULL;
+    char *cp, *cp2;
+    FILE *file;
+    struct exec exec;
+    ElfW(Ehdr) *elf_hdr;
+    struct stat statbuf;
+    char buff[4096];
+
+    /* see if name is of the form libZ.so* */
+    if ((strncmp(name, "lib", 3) == 0 || strncmp(name, "ld-", 3) == 0) && \
+       name[strlen(name)-1] != '~' && (cp = strstr(name, ".so")))
+    {
+       /* find the start of the Vminor part, if any */
+       if (cp[3] == '.' && (cp2 = strchr(cp + 4, '.')))
+           cp = cp2;
+       else
+           cp = cp + strlen(cp);
+
+       /* construct the full path name */
+       sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ?
+               "/" : "", name);
+
+       /* first, make sure it's a regular file */
+       if (lstat(buff, &statbuf))
+           warn("can't lstat %s (%s), skipping", buff, strerror(errno));
+       else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
+           warn("%s is not a regular file or symlink, skipping", buff);
+       else
+       {
+           /* is it a regular file or a symlink */
+           *islink = S_ISLNK(statbuf.st_mode);
+
+           /* then try opening it */
+           if (!(file = fopen(buff, "rb")))
+               warn("can't open %s (%s), skipping", buff, strerror(errno));
+           else
+           {
+               /* now make sure it's a shared library */
+               if (fread(&exec, sizeof exec, 1, file) < 1)
+                   warn("can't read header from %s, skipping", buff);
+               else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC)
+               {
+                   elf_hdr = (ElfW(Ehdr) *) &exec;
+                   if (elf_hdr->e_ident[0] != 0x7f ||
+                       strncmp(&elf_hdr->e_ident[1], "ELF",3) != 0)
+                   {
+                       /* silently ignore linker scripts */
+                       if (strncmp((char *)&exec, "/* GNU ld", 9) != 0)
+                           warn("%s is not a shared library, skipping", buff);
+                   }
+                   else
+                   {
+                       /* always call readsoname to update type */
+                       if(expected_type == LIB_DLL){
+                           warn("%s is not an a.out library, its ELF!\n", buff);
+                           expected_type=LIB_ANY;
+                       }
+                       *type = LIB_ELF;
+                       good = readsoname(buff, file, expected_type, type, 
+                                         elf_hdr->e_ident[EI_CLASS]);
+                       if (good == NULL || *islink)
+                       {
+                           if (good != NULL)
+                               free(good);
+                           good = xstrdup(name);
+                       }
+                       else
+                       {
+                           /* if the soname does not match the filename,
+                              issue a warning, but only in debug mode. */
+                           int len = strlen(good);
+                           if (debug && (strncmp(good, name, len) != 0 ||
+                               (name[len] != '\0' && name[len] != '.')))
+                               warn("%s has inconsistent soname (%s)",
+                                    buff, good);
+                       }
+                   }
+               }
+               else
+               {
+                   if (*islink)
+                       good = xstrdup(name);
+                   else
+                   {
+                       good = xmalloc(cp - name + 1);
+                       strncpy(good, name, cp - name);
+                       good[cp - name] = '\0';
+                   }
+                   if(expected_type != LIB_ANY && expected_type != LIB_DLL)
+                   {
+                       warn("%s is not an ELF library, its an a.out DLL!", buff);
+                       expected_type=LIB_ANY;
+                   }
+                   
+                   *type = LIB_DLL;
+               }
+               fclose(file);
+           }
+       }
+    }
+
+    return good;
+}
+
+/* update the symlink to new library */
+void link_shlib(const char *dir, const char *file, const char *so)
+{
+    int change = 1;
+    char libname[4096];
+    char linkname[4096];
+    struct stat libstat;
+    struct stat linkstat;
+
+    /* construct the full path names */
+    sprintf(libname, "%s/%s", dir, file);
+    sprintf(linkname, "%s/%s", dir, so);
+
+    /* see if a link already exists */
+    if (!stat(linkname, &linkstat))
+    {
+       /* now see if it's the one we want */
+       if (stat(libname, &libstat))
+           warn("can't stat %s (%s)", libname, strerror(errno));
+       else if (libstat.st_dev == linkstat.st_dev &&
+           libstat.st_ino == linkstat.st_ino)
+           change = 0;
+    }
+
+    /* then update the link, if required */
+    if (change > 0 && !nolinks)
+    {
+       if (!lstat(linkname, &linkstat))
+       {
+         if (!S_ISLNK(linkstat.st_mode))
+         {
+           warn("%s is not a symlink", linkname);
+           change = -1;
+         }
+         else if (remove(linkname))
+         {
+           warn("can't unlink %s (%s)", linkname, strerror(errno));
+           change = -1;
+         }
+       }
+       if (change > 0)
+       {
+         if (symlink(file, linkname))
+         {
+           warn("can't link %s to %s (%s)", linkname, file, strerror(errno));
+           change = -1;
+         }
+       }
+    }
+
+    /* some people like to know what we're doing */
+    if (verbose > 0)
+       printf("\t%s => %s%s\n", so, file,
+              change < 0 ? " (SKIPPED)" :
+              (change > 0 ? " (changed)" : ""));
+
+    return;
+}
+
+/* figure out which library is greater */
+int libcmp(char *p1, char *p2)
+{
+    while (*p1)
+    {
+       if (isdigit(*p1) && isdigit(*p2))
+       {
+           /* must compare this numerically */
+           int v1, v2;
+           v1 = strtoul(p1, &p1, 10);
+           v2 = strtoul(p2, &p2, 10);
+           if (v1 != v2)
+               return v1 - v2;
+       }
+       else if (isdigit(*p1) && !isdigit(*p2))
+           return 1;
+       else if (!isdigit(*p1) && isdigit(*p2))
+           return -1;
+       else if (*p1 != *p2)
+           return *p1 - *p2;
+       else
+           p1++, p2++;
+    }
+
+    return *p1 - *p2;
+}
+
+struct lib
+{
+    char *so;                  /* soname of a library */
+    char *name;                        /* name of a library */
+    int libtype;               /* type of a library */
+    int islink;                        /* is it a symlink */
+    struct lib *next;          /* next library in list */
+};
+
+/* update all shared library links in a directory */
+void scan_dir(const char *name)
+{
+    DIR *dir;
+    struct dirent *ent;
+    char *so;
+    struct lib *lp, *libs = NULL;
+    int libtype, islink;
+    int expected_type = LIB_ANY;
+    char *t;
+
+    /* Check for an embedded expected type */
+    t=strrchr(name, '=');
+    if( t )
+    {
+       *t++ = '\0'; /* Skip = char */
+       if(strcasecmp(t, "libc4") == 0)
+       {
+           expected_type = LIB_DLL;
+       } 
+       else
+       {
+           if(strcasecmp(t, "libc5") == 0)
+           {
+               expected_type = LIB_ELF_LIBC5; 
+           }
+           else
+           {
+               if(strcasecmp(t, "libc6") == 0)
+               {
+                   expected_type = LIB_ELF_LIBC6;
+               }
+               else
+               {
+                   warn("Unknown type field '%s' for dir '%s' - ignored\n", t, name);
+                   expected_type = LIB_ANY;
+               }
+           }
+       }
+    }
+
+    /* let 'em know what's going on */
+    if (verbose > 0)
+       printf("%s:\n", name);
+
+    /* if we can't open it, we can't do anything */
+    if ((dir = opendir(name)) == NULL)
+    {
+       warn("can't open %s (%s), skipping", name, strerror(errno));
+       return;
+    }
+
+    /* yes, we have to look at every single file */
+    while ((ent = readdir(dir)) != NULL)
+    {
+       /* if it's not a shared library, don't bother */
+       if ((so = is_shlib(name, ent->d_name, &libtype, &islink, expected_type)) == NULL)
+           continue;
+
+       /* have we already seen one with the same so name? */
+       for (lp = libs; lp; lp = lp->next)
+       {
+           if (strcmp(so, lp->so) == 0)
+           {
+               /* we have, which one do we want to use? */
+               if ((!islink && lp->islink) ||
+                   (islink == lp->islink && 
+                    libcmp(ent->d_name, lp->name) > 0))
+               {
+                   /* let's use the new one */
+                   free(lp->name);
+                   lp->name = xstrdup(ent->d_name);
+                   lp->libtype = libtype;
+                   lp->islink = islink;
+               } 
+               break;
+           }
+       }
+
+       /* congratulations, you're the first one we've seen */
+       if (!lp)
+       {
+           lp = xmalloc(sizeof *lp);
+           lp->so = xstrdup(so);
+           lp->name = xstrdup(ent->d_name);
+           lp->libtype = libtype;
+           lp->islink = islink;
+           lp->next = libs;
+           libs = lp;
+       }
+
+       free(so);
+    }
+
+    /* don't need this any more */
+    closedir(dir);
+
+    /* now we have all the latest libs, update the links */
+    for (lp = libs; lp; lp = lp->next)
+    {
+        if (!lp->islink)
+           link_shlib(name, lp->name, lp->so);
+       if (!nocache)
+           cache_dolib(name, lp->so, lp->libtype);
+    }
+
+    /* always try to clean up after ourselves */
+    while (libs)
+    {
+       lp = libs->next;
+       free(libs->so);
+       free(libs->name);
+       free(libs);
+       libs = lp;
+    }
+
+    return;
+}
+
+/* return the list of system-specific directories */
+char *get_extpath(void)
+{
+    char *res = NULL, *cp;
+    FILE *file;
+    struct stat stat;
+
+    if ((file = fopen(conffile, "r")) != NULL)
+    {
+       fstat(fileno(file), &stat);
+       res = xmalloc(stat.st_size + 1);
+       fread(res, 1, stat.st_size, file);
+       fclose(file);
+       res[stat.st_size] = '\0';
+
+       /* convert comments fo spaces */
+       for (cp = res; *cp; /*nada*/) {
+         if (*cp == '#') {
+           do
+             *cp++ = ' ';
+           while (*cp && *cp != '\n');
+         } else {
+           cp++;
+         }
+       }         
+    }
+
+    return res;
+}
+
+void usage(void)
+{
+    fprintf(stderr,
+           "ldconfig - update shared library symlinks\n"
+           "\n"
+           "usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...\n"
+           "       ldconfig -l [-Dv] lib ...\n"
+           "       ldconfig -p\n"
+           "\t-D:\t\tdebug mode, don't update links\n"
+           "\t-v:\t\tverbose mode, print things as we go\n"
+           "\t-q:\t\tquiet mode, don't print warnings\n"
+           "\t-n:\t\tdon't process standard directories\n"
+           "\t-N:\t\tdon't update the library cache\n"
+           "\t-X:\t\tdon't update the library links\n"
+           "\t-l:\t\tlibrary mode, manually link libraries\n"
+           "\t-p:\t\tprint the current library cache\n"
+           "\t-f conf :\tuse conf instead of %s\n"
+           "\t-C cache:\tuse cache instead of %s\n"
+           "\t-r root :\tfirst, do a chroot to the indicated directory\n"
+           "\tdir ... :\tdirectories to process\n"
+           "\tlib ... :\tlibraries to link\n"
+           "\n"
+           "Copyright 1994-2000 David Engel and Mitch D'Souza\n",
+           LDSO_CONF, LDSO_CACHE
+           );
+    exit(EXIT_FATAL);
+}
+
+int main(int argc, char **argv)
+{
+    int i, c;
+    int nodefault = 0;
+    int printcache = 0;
+    char *cp, *dir, *so;
+    char *extpath;
+    int libtype, islink;
+    char *chroot_dir = NULL;
+
+    prog = argv[0];
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "DvqnNXlpf:C:r:")) != EOF)
+       switch (c)
+       {
+       case 'D':
+           debug = 1;          /* debug mode */
+           nocache = 1;
+           nolinks = 1;
+           verbose = 1;
+           break;
+       case 'v':
+           verbose = 1;        /* verbose mode */
+           break;
+       case 'q':
+           if (verbose <= 0)
+               verbose = -1;   /* quiet mode */
+           break;
+       case 'n':
+           nodefault = 1;      /* no default dirs */
+           nocache = 1;
+           break;
+       case 'N':
+           nocache = 1;        /* don't build cache */
+           break;
+       case 'X':
+           nolinks = 1;        /* don't update links */
+           break;
+       case 'l':
+           libmode = 1;        /* library mode */
+           break;
+       case 'p':
+           printcache = 1;     /* print cache */
+           break;
+       case 'f':
+           conffile = optarg;  /* alternate conf file */
+           break;
+       case 'C':
+           cachefile = optarg; /* alternate cache file */
+           break;
+       case 'r':
+           chroot_dir = optarg;
+           break;
+       default:
+           usage();
+           break;
+
+       /* THE REST OF THESE ARE UNDOCUMENTED AND MAY BE REMOVED
+          IN FUTURE VERSIONS. */
+       }
+
+    if (chroot_dir && *chroot_dir) {
+       if (chroot(chroot_dir) < 0)
+           error("couldn't chroot to %s (%s)", chroot_dir, strerror(errno));
+        if (chdir("/") < 0)
+           error("couldn't chdir to / (%s)", strerror(errno));
+    }
+
+    /* allow me to introduce myself, hi, my name is ... */
+    if (verbose > 0)
+       printf("%s: version %s\n", argv[0], VERSION);
+
+    if (printcache)
+    {
+       /* print the cache -- don't you trust me? */
+       cache_print();
+       exit(EXIT_OK);
+    }
+    else if (libmode)
+    {
+       /* so you want to do things manually, eh? */
+
+       /* ok, if you're so smart, which libraries do we link? */
+       for (i = optind; i < argc; i++)
+       {
+           /* split into directory and file parts */
+           if (!(cp = strrchr(argv[i], '/')))
+           {
+               dir = ".";      /* no dir, only a filename */
+               cp = argv[i];
+           }
+           else
+           {
+               if (cp == argv[i])
+                   dir = "/";  /* file in root directory */
+               else
+                   dir = argv[i];
+               *cp++ = '\0';   /* neither of the above */
+           }
+
+           /* we'd better do a little bit of checking */
+           if ((so = is_shlib(dir, cp, &libtype, &islink, LIB_ANY)) == NULL)
+               error("%s%s%s is not a shared library", dir,
+                     (*dir && strcmp(dir, "/")) ? "/" : "", cp);
+
+           /* so far, so good, maybe he knows what he's doing */
+           link_shlib(dir, cp, so);
+       }
+    }
+    else
+    {
+       /* the lazy bum want's us to do all the work for him */
+
+       /* don't cache dirs on the command line */
+       int nocache_save = nocache;
+       nocache = 1;
+
+       /* OK, which directories should we do? */
+       for (i = optind; i < argc; i++)
+           scan_dir(argv[i]);
+
+       /* restore the desired caching state */
+       nocache = nocache_save;
+
+       /* look ma, no defaults */
+       if (!nodefault)
+       {
+           /* I guess the defaults aren't good enough */
+           if ((extpath = get_extpath()))
+           {
+               for (cp = strtok(extpath, DIR_SEP); cp;
+                    cp = strtok(NULL, DIR_SEP))
+                   scan_dir(cp);
+               free(extpath);
+           }
+
+#ifdef UCLIBC_DEVEL
+           scan_dir(UCLIBC_INSTALL_DIR"/lib");
+#else
+           /* everybody needs these, don't they? */
+           scan_dir("/usr/lib");
+           scan_dir("/lib");
+#endif
+       }
+
+       if (!nocache)
+           cache_write();
+    }
+
+    exit(EXIT_OK);
+}
+
+typedef struct liblist
+{
+    int flags;
+    int sooffset;
+    int liboffset;
+    char *soname;
+    char *libname;
+    struct liblist *next;
+} liblist_t;
+
+static header_t magic = { LDSO_CACHE_MAGIC, LDSO_CACHE_VER, 0 };
+static liblist_t *lib_head = NULL;
+
+static int liblistcomp(liblist_t *x, liblist_t *y)
+{
+    int res;
+
+    if ((res = libcmp(x->soname, y->soname)) == 0)
+    {
+        res = libcmp(strrchr(x->libname, '/') + 1,
+                    strrchr(y->libname, '/') + 1);
+    }
+
+    return res;
+}
+
+void cache_dolib(const char *dir, const char *so, int libtype)
+{
+    char fullpath[PATH_MAX];
+    liblist_t *new_lib, *cur_lib;
+
+    magic.nlibs++;
+    sprintf(fullpath, "%s/%s", dir, so);
+    new_lib = xmalloc(sizeof (liblist_t));
+    new_lib->flags = libtype;
+    new_lib->soname = xstrdup(so);
+    new_lib->libname = xstrdup(fullpath);
+
+    if (lib_head == NULL || liblistcomp(new_lib, lib_head) > 0)
+    {
+        new_lib->next = lib_head;
+       lib_head = new_lib;
+    }
+    else
+    {
+        for (cur_lib = lib_head; cur_lib->next != NULL &&
+            liblistcomp(new_lib, cur_lib->next) <= 0;
+            cur_lib = cur_lib->next)
+           /* nothing */;
+       new_lib->next = cur_lib->next;
+       cur_lib->next = new_lib;
+    }
+}
+
+void cache_write(void)
+{
+    int cachefd;
+    int stroffset = 0;
+    char tempfile[4096];
+    liblist_t *cur_lib;
+
+    if (!magic.nlibs)
+       return;
+
+    sprintf(tempfile, "%s~", cachefile);
+
+    if (unlink(tempfile) && errno != ENOENT)
+        error("can't unlink %s (%s)", tempfile, strerror(errno));
+
+    if ((cachefd = creat(tempfile, 0644)) < 0)
+       error("can't create %s (%s)", tempfile, strerror(errno));
+
+    if (write(cachefd, &magic, sizeof (header_t)) != sizeof (header_t))
+       error("can't write %s (%s)", tempfile, strerror(errno));
+
+    for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
+    {
+        cur_lib->sooffset = stroffset;
+       stroffset += strlen(cur_lib->soname) + 1;
+       cur_lib->liboffset = stroffset;
+       stroffset += strlen(cur_lib->libname) + 1;
+       if (write(cachefd, cur_lib, sizeof (libentry_t)) !=
+           sizeof (libentry_t))
+           error("can't write %s (%s)", tempfile, strerror(errno));
+    }
+
+    for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
+    {
+      if (write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1)
+         != strlen(cur_lib->soname) + 1)
+         error("can't write %s (%s)", tempfile, strerror(errno));
+      if (write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1)
+         != strlen(cur_lib->libname) + 1)
+         error("can't write %s (%s)", tempfile, strerror(errno));
+    }
+
+    if (close(cachefd))
+        error("can't close %s (%s)", tempfile, strerror(errno));
+
+    if (chmod(tempfile, 0644))
+       error("can't chmod %s (%s)", tempfile, strerror(errno));
+
+    if (rename(tempfile, cachefile))
+       error("can't rename %s (%s)", tempfile, strerror(errno));
+}
+
+void cache_print(void)
+{
+    caddr_t c;
+    struct stat st;
+    int fd = 0;
+    char *strs;
+    header_t *header;
+    libentry_t *libent;
+
+    if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY))<0)
+       error("can't read %s (%s)", cachefile, strerror(errno));
+    if ((c = mmap(0,st.st_size, PROT_READ, MAP_SHARED ,fd, 0)) == (caddr_t)-1)
+       error("can't map %s (%s)", cachefile, strerror(errno));
+    close(fd);
+
+    if (memcmp(((header_t *)c)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
+       error("%s cache corrupt", cachefile);
+
+    if (memcmp(((header_t *)c)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
+       error("wrong cache version - expected %s", LDSO_CACHE_VER);
+
+    header = (header_t *)c;
+    libent = (libentry_t *)(c + sizeof (header_t));
+    strs = (char *)&libent[header->nlibs];
+
+    printf("%d libs found in cache `%s' (version %s)\n",
+           header->nlibs, cachefile, LDSO_CACHE_VER);
+
+    for (fd = 0; fd < header->nlibs; fd++)
+    {
+       printf("\t%s ", strs + libent[fd].sooffset);
+       switch (libent[fd].flags & ~LIB_ELF64) 
+       {
+         case LIB_DLL:
+           printf("(libc4)");
+           break;
+         case LIB_ELF:
+           printf("(ELF%s)", libent[fd].flags & LIB_ELF64 ? "/64" : "");
+           break;
+         case LIB_ELF_LIBC5:
+         case LIB_ELF_LIBC6:
+           printf("(libc%d%s)", (libent[fd].flags & ~LIB_ELF64) + 3,
+                  libent[fd].flags & LIB_ELF64 ? "/64" : "");
+           break;
+         default:
+           printf("(unknown)");
+           break;
+       }
+       printf(" => %s\n", strs + libent[fd].liboffset);
+    }
+
+    munmap (c,st.st_size);
+}
+
diff --git a/ldso/util/ldd.c b/ldso/util/ldd.c
new file mode 100644 (file)
index 0000000..62c479b
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * ldd - print shared library dependencies
+ *
+ * usage: ldd [-vVdr] prog ...
+ *        -v: print ldd version
+ *        -V: print ld.so version
+ *       -d: Perform relocations and report any missing functions. (ELF only).
+ *       -r: Perform relocations for both data objects and functions, and
+ *           report any missing objects (ELF only).
+ *        prog ...: programs to check
+ *
+ * Copyright 1993-2000, David Engel
+ *
+ * This program may be used for any purpose as long as this
+ * copyright notice is kept.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <a.out.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <linux/elf.h>
+#include "../config.h"
+#include "readelf.h"
+
+#ifdef __GNUC__
+void warn(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void error(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+#endif
+
+char *prog = NULL;
+
+void warn(char *fmt, ...)
+{
+    va_list ap;
+
+    fflush(stdout);    /* don't mix output and error messages */
+    fprintf(stderr, "%s: warning: ", prog);
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\n");
+
+    return;
+}
+
+void error(char *fmt, ...)
+{
+    va_list ap;
+
+    fflush(stdout);    /* don't mix output and error messages */
+    fprintf(stderr, "%s: ", prog);
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+
+    fprintf(stderr, "\n");
+
+    exit(1);
+}
+
+void *xmalloc(size_t size)
+{
+    void *ptr;
+    if ((ptr = malloc(size)) == NULL)
+       error("out of memory");
+    return ptr;
+}
+
+char *xstrdup(char *str)
+{
+    char *ptr;
+    if ((ptr = strdup(str)) == NULL)
+       error("out of memory");
+    return ptr;
+}
+
+/* see if prog is a binary file */
+int is_bin(char *argv0, char *prog)
+{
+    int res = 0;
+    FILE *file;
+    struct exec exec;
+    char *cp;
+    int libtype;
+
+    /* must be able to open it for reading */
+    if ((file = fopen(prog, "rb")) == NULL)
+       fprintf(stderr, "%s: can't open %s (%s)\n", argv0, prog,
+               strerror(errno));
+    else
+    {
+       /* then see if it's Z, Q or OMAGIC */
+       if (fread(&exec, sizeof exec, 1, file) < 1)
+           fprintf(stderr, "%s: can't read header from %s\n", argv0, prog);
+       else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
+                 N_MAGIC(exec) != OMAGIC)
+       {
+           struct elfhdr elf_hdr;
+           
+           rewind(file);
+           fread(&elf_hdr, sizeof elf_hdr, 1, file);
+           if (elf_hdr.e_ident[0] != 0x7f ||
+               strncmp(elf_hdr.e_ident+1, "ELF", 3) != 0)
+               fprintf(stderr, "%s: %s is not a.out or ELF\n", argv0, prog);
+           else
+           {
+               struct elf_phdr phdr;
+               int i;
+
+               /* Check its an exectuable, library or other */
+               switch (elf_hdr.e_type)
+               {
+                 case ET_EXEC:
+                   res = 3;
+                   /* then determine if it is dynamic ELF */
+                   for (i=0; i<elf_hdr.e_phnum; i++)
+                   {
+                       fread(&phdr, sizeof phdr, 1, file);
+                       if (phdr.p_type == PT_DYNAMIC)
+                       {
+                           res = 2;
+                           break;
+                       }
+                   }
+                   break;
+                 case ET_DYN:
+                   if ((cp = readsoname(prog, file, LIB_ANY, &libtype, 
+                        elf_hdr.e_ident[EI_CLASS])) != NULL)
+                       free(cp);
+                   if (libtype == LIB_ELF_LIBC5)
+                       res = 5;
+                   else
+                       res = 4;
+                   break;
+                 default:
+                   res = 0;
+                   break;
+               }
+           }
+       }
+       else
+           res = 1; /* looks good */
+
+       fclose(file);
+    }
+    return res;
+}
+
+int main(int argc, char **argv, char **envp)
+{
+    int i;
+    int vprinted = 0;
+    int resolve = 0;
+    int bind = 0;
+    int bintype;
+    char *ld_preload;
+    int status = 0;
+
+    /* this must be volatile to work with -O, GCC bug? */
+    volatile loadptr loader = (loadptr)LDSO_ADDR;
+  
+    prog = argv[0];
+
+    while ((i = getopt(argc, argv, "drvV")) != EOF)
+       switch (i)
+       {
+       case 'v':
+           /* print our version number */
+           printf("%s: version %s\n", argv[0], VERSION);
+           vprinted = 1;
+           break;
+       case 'd':
+           bind = 1;
+           break;
+       case 'r':
+           resolve = 1;
+           break;
+       case 'V':
+           /* print the version number of ld.so */
+           if (uselib(LDSO_IMAGE))
+           {
+               fprintf(stderr, "%s: can't load dynamic linker %s (%s)\n",
+                       argv[0], LDSO_IMAGE, strerror(errno));
+               exit(1);
+           }
+           loader(FUNC_VERS, NULL);
+           vprinted = 1;
+           break;
+       }
+
+    /* must specify programs if -v or -V not used */
+    if (optind >= argc && !vprinted)
+    {
+       printf("usage: %s [-vVdr] prog ...\n", argv[0]);
+       exit(0);
+    }
+
+    /* setup the environment for ELF binaries */
+    putenv("LD_TRACE_LOADED_OBJECTS=1");
+    if (resolve || bind)
+        putenv("LD_BIND_NOW=1");
+    if (resolve)
+        putenv("LD_WARN=1");
+    ld_preload = getenv("LD_PRELOAD");
+
+    /* print the dependencies for each program */
+    for (i = optind; i < argc; i++)
+    {
+       pid_t pid;
+       char buff[1024];
+
+       /* make sure it's a binary file */
+       if (!(bintype = is_bin(argv[0], argv[i])))
+       {
+           status = 1;
+           continue;
+       }
+
+       /* print the program name if doing more than one */
+       if (optind < argc-1)
+       {
+           printf("%s:\n", argv[i]);
+           fflush(stdout);
+       }
+
+       /* no need to fork/exec for static ELF program */
+       if (bintype == 3)
+       {
+           printf("\tstatically linked (ELF)\n");
+           continue;
+       }
+
+       /* now fork and exec prog with argc = 0 */
+       if ((pid = fork()) < 0)
+       {
+           fprintf(stderr, "%s: can't fork (%s)\n", argv[0], strerror(errno));
+           exit(1);
+       }
+       else if (pid == 0)
+       {
+           switch (bintype)
+           {
+             case 1: /* a.out */
+               /* save the name in the enviroment, ld.so may need it */
+               snprintf(buff, sizeof buff, "%s=%s", LDD_ARGV0, argv[i]);
+               putenv(buff);
+               execl(argv[i], NULL);
+               break;
+             case 2: /* ELF program */
+               execl(argv[i], argv[i], NULL);
+               break;
+             case 4: /* ELF libc6 library */
+               /* try to use /lib/ld-linux.so.2 first */
+#if !defined(__mc68000__)
+               execl("/lib/ld-linux.so.2", "/lib/ld-linux.so.2", 
+                     "--list", argv[i], NULL);
+#else
+               execl("/lib/ld.so.1", "/lib/ld.so.1", 
+                     "--list", argv[i], NULL);
+#endif
+               /* fall through */
+             case 5: /* ELF libc5 library */
+               /* if that fails, add library to LD_PRELOAD and 
+                  then execute lddstub */
+               if (ld_preload && *ld_preload)
+                   snprintf(buff, sizeof buff, "LD_PRELOAD=%s:%s%s", 
+                            ld_preload, *argv[i] == '/' ? "" : "./", argv[i]);
+               else
+                   snprintf(buff, sizeof buff, "LD_PRELOAD=%s%s", 
+                            *argv[i] == '/' ? "" : "./", argv[i]);
+               putenv(buff);
+               execl(LDDSTUB, argv[i], NULL);
+               break;
+             default:
+               fprintf(stderr, "%s: internal error, bintype = %d\n",
+                       argv[0], bintype);
+               exit(1);
+           }
+           fprintf(stderr, "%s: can't execute %s (%s)\n", argv[0], argv[i],
+                   strerror(errno));
+           exit(1);
+       }
+       else
+       {
+           /* then wait for it to complete */
+           int status;
+           if (waitpid(pid, &status, 0) != pid)
+           {
+               fprintf(stderr, "%s: error waiting for %s (%s)\n", argv[0], 
+                       argv[i], strerror(errno));
+           }
+           else if (WIFSIGNALED(status))
+           {
+               fprintf(stderr, "%s: %s exited with signal %d\n", argv[0], 
+                       argv[i], WTERMSIG(status));
+           }
+       }
+    }
+
+    exit(status);
+}
diff --git a/ldso/util/lddstub.S b/ldso/util/lddstub.S
new file mode 100644 (file)
index 0000000..33a67ee
--- /dev/null
@@ -0,0 +1,42 @@
+       .text
+.globl main
+.globl exit
+main:
+exit:
+#if defined(__i386__)
+       movl $1,%eax
+       movl $0,%ebx
+       int  $0x80
+#elif defined(__mc68000__)
+        movel #1,%d0
+        clrl %d1
+        trap #0
+#elif defined(__sparc__)
+       mov  1,%g1
+       mov  0,%o0
+       t    0x10
+#else
+#error Only know how to support i386, m68k and sparc architectures
+#endif
+
+.globl atexit
+.globl __libc_init
+.globl __setfpucw
+atexit:
+__libc_init:
+__setfpucw:
+#if defined(__i386__)
+       ret
+#elif defined(__mc68000__)
+        rts
+#elif defined(__sparc__)
+       ret
+       nop
+#else
+#error Only know how to support i386, m68k and sparc architectures
+#endif
+
+       .data
+.globl __fpu_control
+__fpu_control:
+       .long   0
diff --git a/ldso/util/readelf.c b/ldso/util/readelf.c
new file mode 100644 (file)
index 0000000..ba93d2d
--- /dev/null
@@ -0,0 +1,61 @@
+/* adapted from Eric Youngdale's readelf program */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <link.h>
+#include <elf.h>
+#include <unistd.h>
+#include "../config.h"
+#include "readelf.h"
+#include <sys/types.h>
+
+void warn(char *fmt, ...);
+char *xstrdup(char *);
+
+struct needed_tab
+{
+  char *soname;
+  int type;
+};
+
+struct needed_tab needed_tab[] = {
+  { "libc.so.5",    LIB_ELF_LIBC5 },
+  { "libm.so.5",    LIB_ELF_LIBC5 },
+  { "libdl.so.1",   LIB_ELF_LIBC5 },
+  { "libc.so.6",    LIB_ELF_LIBC6 },
+  { "libm.so.6",    LIB_ELF_LIBC6 },
+  { "libdl.so.2",   LIB_ELF_LIBC6 },
+  { NULL,           LIB_ELF }
+};
+
+char *readsoname(char *name, FILE *infile, int expected_type, 
+                int *type, int elfclass)
+{
+  char *res;
+
+  if (elfclass == ELFCLASS32)
+    res = readsoname32(name, infile, expected_type, type);
+  else
+  {
+    res = readsoname64(name, infile, expected_type, type);
+#if 0
+    *type |= LIB_ELF64;
+#endif
+  }
+
+  return res;
+}
+
+#undef __ELF_NATIVE_CLASS
+#undef readsonameXX
+#define readsonameXX readsoname32
+#define __ELF_NATIVE_CLASS 32
+#include "readelf2.c"
+
+#undef __ELF_NATIVE_CLASS
+#undef readsonameXX
+#define readsonameXX readsoname64
+#define __ELF_NATIVE_CLASS 64
+#include "readelf2.c"
diff --git a/ldso/util/readelf.h b/ldso/util/readelf.h
new file mode 100644 (file)
index 0000000..78d2216
--- /dev/null
@@ -0,0 +1,4 @@
+char *readsoname(char *name, FILE *file, int expected_type, 
+                int *type, int elfclass);
+char *readsoname32(char *name, FILE *file, int expected_type, int *type);
+char *readsoname64(char *name, FILE *file, int expected_type, int *type);
diff --git a/ldso/util/readelf2.c b/ldso/util/readelf2.c
new file mode 100644 (file)
index 0000000..1bf47b7
--- /dev/null
@@ -0,0 +1,115 @@
+char *readsonameXX(char *name, FILE *infile, int expected_type, int *type)
+{
+  ElfW(Ehdr) *epnt;
+  ElfW(Phdr) *ppnt;
+  int i, j;
+  char *header;
+  ElfW(Word) dynamic_addr = 0;
+  ElfW(Word) dynamic_size = 0;
+  unsigned long page_size = getpagesize();
+  ElfW(Word) strtab_val = 0;
+  ElfW(Word) needed_val;
+  ElfW(Sword) loadaddr = -1;
+  ElfW(Dyn) *dpnt;
+  struct stat st;
+  char *needed;
+  char *soname = NULL;
+  int multi_libcs = 0;
+
+  if(expected_type == LIB_DLL)
+    {
+      warn("%s does not match type specified for directory!", name);
+      expected_type = LIB_ANY;
+    }
+
+  *type = LIB_ELF;
+
+  if (fstat(fileno(infile), &st))
+    return NULL;
+  header = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fileno(infile), 0);
+  if (header == (caddr_t)-1)
+    return NULL;
+
+  epnt = (ElfW(Ehdr) *)header;
+  if ((char *)(epnt+1) > (char *)(header + st.st_size))
+    goto skip;
+
+  ppnt = (ElfW(Phdr) *)&header[epnt->e_phoff];
+  if ((char *)ppnt < (char *)header ||
+      (char *)(ppnt+epnt->e_phnum) > (char *)(header + st.st_size))
+    goto skip;
+
+  for(i = 0; i < epnt->e_phnum; i++)
+  {
+    if (loadaddr == -1 && ppnt->p_type == PT_LOAD) 
+      loadaddr = (ppnt->p_vaddr & ~(page_size-1)) -
+       (ppnt->p_offset & ~(page_size-1));
+    if(ppnt->p_type == 2)
+    {
+      dynamic_addr = ppnt->p_offset;
+      dynamic_size = ppnt->p_filesz;
+    };
+    ppnt++;
+  };
+    
+  dpnt = (ElfW(Dyn) *) &header[dynamic_addr];
+  dynamic_size = dynamic_size / sizeof(ElfW(Dyn));
+  if ((char *)dpnt < (char *)header ||
+      (char *)(dpnt+dynamic_size) > (char *)(header + st.st_size))
+    goto skip;
+  
+  while (dpnt->d_tag != DT_NULL)
+  {
+    if (dpnt->d_tag == DT_STRTAB)
+      strtab_val = dpnt->d_un.d_val;
+    dpnt++;
+  };
+
+  if (!strtab_val)
+    goto skip;
+
+  dpnt = (ElfW(Dyn) *) &header[dynamic_addr];
+  while (dpnt->d_tag != DT_NULL)
+  {
+    if (dpnt->d_tag == DT_SONAME || dpnt->d_tag == DT_NEEDED)
+    {
+      needed_val = dpnt->d_un.d_val;
+      if (needed_val + strtab_val - loadaddr >= 0 ||
+         needed_val + strtab_val - loadaddr < st.st_size)
+      {
+       needed = (char *) (header - loadaddr + strtab_val + needed_val);
+
+       if (dpnt->d_tag == DT_SONAME)
+         soname = xstrdup(needed);
+
+       for (j = 0; needed_tab[j].soname != NULL; j++)
+       {
+         if (strcmp(needed, needed_tab[j].soname) == 0)
+         {
+           if (*type != LIB_ELF && *type != needed_tab[j].type)
+             multi_libcs = 1;
+           *type = needed_tab[j].type;
+         }
+       }
+      }
+    }
+    dpnt++;
+  };
+  
+  if (multi_libcs)
+    warn("%s appears to be for multiple libc's", name);
+
+  /* If we could not deduce the libc type, and we know what to expect, set the type */
+  if(*type == LIB_ELF && expected_type != LIB_ANY) *type = expected_type;
+
+  if(expected_type != LIB_ANY && expected_type != LIB_ELF && 
+     expected_type != *type)
+  {
+      warn("%s does not match type specified for directory!", name);
+  }
+
+ skip:
+  munmap(header, st.st_size);
+
+  return soname;
+}