OK, this is the dynamic loader for the MIPS. It's a hack, it's GPL'd, its
authorpefo <pefo@openbsd.org>
Wed, 18 Sep 1996 08:15:16 +0000 (08:15 +0000)
committerpefo <pefo@openbsd.org>
Wed, 18 Sep 1996 08:15:16 +0000 (08:15 +0000)
just ugly, but it works. So we stick with it right now...

43 files changed:
gnu/libexec/ld.so/COPYRIGHT [new file with mode: 0644]
gnu/libexec/ld.so/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/README [new file with mode: 0644]
gnu/libexec/ld.so/config.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/boot1.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/hash.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/hash.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/elfinterp.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/resolve.S [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/string.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/syscall.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/i386/sysdep.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/ld.so.8 [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/elfinterp.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/resolve.S [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/string.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/syscall.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/m68k/sysdep.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/elf-machine.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/elf.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/elf_abi.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/elfinterp.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/link.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/string.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/syscall.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/mips/sysdep.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/readelflib1.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/elfinterp.c [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/resolve.S [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/string.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/syscall.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/sparc/sysdep.h [new file with mode: 0644]
gnu/libexec/ld.so/ld.so/vsprintf.c [new file with mode: 0644]
gnu/libexec/ld.so/ldconfig/Makefile [new file with mode: 0644]
gnu/libexec/ld.so/ldconfig/ld.so.conf [new file with mode: 0644]
gnu/libexec/ld.so/ldconfig/ldconfig.8 [new file with mode: 0644]
gnu/libexec/ld.so/ldconfig/ldconfig.c [new file with mode: 0644]
gnu/libexec/ld.so/ldconfig/readelf.c [new file with mode: 0644]

diff --git a/gnu/libexec/ld.so/COPYRIGHT b/gnu/libexec/ld.so/COPYRIGHT
new file mode 100644 (file)
index 0000000..37d2780
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994 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/gnu/libexec/ld.so/Makefile b/gnu/libexec/ld.so/Makefile
new file mode 100644 (file)
index 0000000..ea87f2c
--- /dev/null
@@ -0,0 +1,5 @@
+#      $OpenBSD: Makefile,v 1.1 1996/09/18 08:15:19 pefo Exp $
+
+SUBDIR= ldconfig ld.so
+
+.include <bsd.subdir.mk>
diff --git a/gnu/libexec/ld.so/README b/gnu/libexec/ld.so/README
new file mode 100644 (file)
index 0000000..51bcc51
--- /dev/null
@@ -0,0 +1,311 @@
+This package contains my shared, dynamic linker (ld.so) and utilities
+(ldconfig and ldd) for Linux.
+
+For those that were not involved in the development of ld.so, its main
+feature is that the user-level, shared library and dynamic linking
+support has been moved to its own, special shared library.  This has
+two significant advantages.  First, the startup code for all binaries,
+which must be linked statically, is reduced by about 2.5k.  Second,
+and probably more important, the shared library and dynamic linking
+support can be upgraded for all binaries without having to relink by
+simply installing a new ld.so.
+
+In addition to ld.so, this package also includes two, related
+utilities, ldconfig and ldd.  Ldconfig is used to automatically update
+symbolic links to shared libraries and build the library cache used by
+ld.so.  This should hopefully put an end to the common problem of
+accidentally deleting a critical library link (eg. /lib/libc.so.4).
+Ldd is used to list the shared libraries dependencies for a binary.
+
+In order to use the debugging, library version of ld.so, the program
+must be explcitly linked with the static libc.a.
+
+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.
+
+Both a.out and ELF versions of gcc, binutils and libc are currently
+needed to recompile everything.  If the ELF version is installed as
+the default, set the value of GCC_DEFAULT to 'elf' in Config.mk,
+otherwise, either leave it undefined or set it to a.out.  Furthermore,
+optimization level O2 or higher must be used to recompile ld-linux.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).
+
+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.
+
+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@ods.com
diff --git a/gnu/libexec/ld.so/config.h b/gnu/libexec/ld.so/config.h
new file mode 100644 (file)
index 0000000..8d571be
--- /dev/null
@@ -0,0 +1,46 @@
+#ifdef DEBUG
+#  define LDSO_IMAGE "../ld-so/ld.so"
+#  define LDSO_CONF  "../util/ld.so.conf"
+#  define LDSO_CACHE "../util/ld.so.cache"
+#else
+#  define LDSO_IMAGE "/lib/ld.so"
+#  define LDSO_CONF  "/etc/ld.so.conf"
+#  define LDSO_CACHE "/var/run/ld.so.cache"
+#endif
+
+#define LDD_ARGV0    "__LDD_ARGV0"
+#define DIR_SEP      ":, \t\n"
+#define MAX_DIRS     32
+
+#define        VERSION "1.0"
+
+typedef void (*loadptr)(int func, ...);
+typedef void (*callbackptr)(int ver, int nlibs, char **libs, 
+               int nmods, char **mods);
+
+#define CALLBACK_VER 1
+
+#define LIB_DLL      0
+#define LIB_ELF      1
+
+#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/gnu/libexec/ld.so/ld.so/Makefile b/gnu/libexec/ld.so/ld.so/Makefile
new file mode 100644 (file)
index 0000000..3ea83da
--- /dev/null
@@ -0,0 +1,22 @@
+#      $OpenBSD: Makefile,v 1.1 1996/09/18 08:15:23 pefo Exp $
+
+SUBDIR= # libdl
+
+CFLAGS += -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER \
+       -DUSE_CACHE -D__PIC__ -I${MACHINE_ARCH}
+
+SRCS=  boot1.c hash.c readelflib1.c vsprintf.c elfinterp.c
+PROG=  ld.so
+MAN=   ld.so.8
+BINDIR=/usr/libexec
+
+.PATH: ${MACHINE_ARCH}
+
+ELF_LDFLAGS=--shared # using GNU ld
+
+$(PROG):
+       $(LD) -x -e _dl_boot $(ELF_LDFLAGS) -o $(DLINKER) $(OBJS)
+
+
+.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/gnu/libexec/ld.so/ld.so/boot1.c b/gnu/libexec/ld.so/ld.so/boot1.c
new file mode 100644 (file)
index 0000000..9b2d78d
--- /dev/null
@@ -0,0 +1,848 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993-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
+
+
+/* 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 <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "hash.h"
+#include <link.h>
+
+#include "sysdep.h"
+#include "syscall.h"
+#include "string.h"
+
+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.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);
+extern void _dl_printhex(int);
+
+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 _dl_runtime_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+extern Elf32_Dyn _DYNAMIC[];
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef Elf32_Rela ELF_RELOC;
+#else
+typedef 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.
+ */
+static void _dl_debug_state()
+{
+  return;
+}
+
+void _dl_boot(void);
+
+void _dl_boot()
+{
+  unsigned int argc;
+  char ** argv, ** envp;
+
+  unsigned int load_addr;
+  unsigned int *aux_dat;
+  int goof = 0;
+  unsigned int *stack;
+  struct elf_resolve * tpnt;
+  struct dyn_elf * rpnt;
+  struct elf_resolve * app_tpnt;
+  unsigned int brk_addr;
+  unsigned int dl_data[10];
+  unsigned char * malloc_buffer, *mmap_zero;
+  int (*_dl_atexit)(void *);
+  int * lpnt;
+  Elf32_Dyn * dpnt;
+  unsigned int *hash_addr;
+  struct r_debug * debug_addr;
+  unsigned int *chains;
+  int indx;
+
+  /* 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, 0);
+
+  stack = aux_dat;     /* Remember this for start later */
+  argc = *(aux_dat);
+  argv = (char **)(aux_dat + 1);
+  aux_dat += argc + 1;  /* 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 */
+  while(*aux_dat)
+    {
+      unsigned int * ad1;
+      ad1 = aux_dat + 1;
+      if( *aux_dat <= AT_ENTRY ) dl_data[*aux_dat] = *ad1;
+      aux_dat += 2;
+    }
+
+  /* Next, locate the GOT */
+
+  load_addr = elf_machine_load_offset();
+
+  GET_GOT(got);
+  dpnt = (Elf32_Dyn *) ((int)_DYNAMIC + 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. */
+
+  mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+                            PROT_READ | PROT_WRITE, 
+                            MAP_ANON | MAP_COPY, -1, 0);
+  if(_dl_mmap_check_error(mmap_zero)) {
+       SEND_STDERR("dl_boot: mmap of zeros 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 != DT_NULL) {
+    if(dpnt->d_tag < DT_NUM) {
+      tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+    }
+    else if(dpnt->d_tag  >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) {
+      tpnt->dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val;
+    }
+    if(dpnt->d_tag == DT_TEXTREL)
+      tpnt->dynamic_info[DT_TEXTREL] = 1;
+    dpnt++;
+  }
+
+  {
+    Elf32_Phdr * ppnt;
+    int i;
+    
+    ppnt = (Elf32_Phdr *) dl_data[AT_PHDR];
+    for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+      if(ppnt->p_type == PT_DYNAMIC) {
+       dpnt = (Elf32_Dyn *) ppnt->p_vaddr;
+       while(dpnt->d_tag != DT_NULL)
+         {
+            if(dpnt->d_tag < DT_NUM) {
+              app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+            }
+            else if(dpnt->d_tag  >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) {
+              app_tpnt->dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val;
+            }
+       /*
+        * We need to store the pointer to the debug data for the
+        * debugger in DYNAMIC if we find a DT_MIPS_RLD_MAP tag. The DYNAMIC
+         * area is write protected so we have to temporary remove
+         * the write protection.
+         */
+           if(dpnt->d_tag == DT_MIPS_RLD_MAP) {
+              caddr_t addr;
+              addr = (caddr_t)((int)dpnt & ~(dl_data[AT_PAGESZ] - 1));
+#if 0
+              _dl_mprotect(addr,dl_data[AT_PAGESZ],PROT_EXEC|PROT_READ|PROT_WRITE);
+#endif
+              *(struct r_debug **)(dpnt->d_un.d_val) = debug_addr;
+#if 0
+              _dl_mprotect(addr,dl_data[AT_PAGESZ],PROT_EXEC|PROT_READ);
+#endif
+            }
+           if(dpnt->d_tag == DT_TEXTREL)
+              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;
+
+  /* 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;
+
+  
+      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]);
+
+
+      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++){
+       Elf32_Sym * symtab;
+       char * strtab;
+       reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+       symtab_index = ELF32_R_SYM(rpnt->r_info);
+       symbol_addr = 0;
+       symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+       strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+       if(symtab_index) {
+
+         /* 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. */
+
+         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, &symtab[symtab_index], 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);
+  lpnt[0] = (int)_dl_runtime_resolve;
+  if(lpnt[1] & 0x80000000)
+    lpnt[1] = (Elf32_Addr) ((unsigned) tpnt | 0x80000000);
+
+  /* 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;
+
+  { Elf32_Ehdr * epnt;
+    Elf32_Phdr * ppnt;
+    int i;
+
+    epnt = (Elf32_Ehdr *) dl_data[AT_BASE];
+    tpnt->n_phent = epnt->e_phnum;
+    tpnt->ppnt = ppnt = (Elf32_Phdr *) ((int)epnt + 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;
+  tpnt->loadoffs = (char *) 0;
+
+  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 */
+
+  {
+    Elf32_Phdr * ppnt;
+    int i;
+
+    ppnt = (Elf32_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) {
+       /* make sure it's really there. */
+       if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+       /* OK, we have what we need - slip this one into the list. */
+       app_tpnt = _dl_add_elf_hash_table("", 0, 0,
+                           app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+       _dl_loaded_modules->libtype = elf_executable;
+       _dl_loaded_modules->ppnt = (Elf32_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]);
+        lpnt[0] = (int)_dl_runtime_resolve;
+        if(lpnt[1] & 0x80000000)
+          lpnt[1] = (Elf32_Addr) ((unsigned) app_tpnt | 0x80000000);
+      }
+      if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+                                        this before */
+       tpnt->libname =  _dl_strdup((char *) ppnt->p_vaddr);
+      }
+    }
+  }
+
+  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);
+
+#ifndef IBCS_COMPATIBLE
+    _dl_preload = _dl_getenv("LD_ELF_PRELOAD", envp);
+    if (!_dl_preload)
+#endif
+      _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+#ifndef IBCS_COMPATIBLE
+    _dl_library_path = _dl_getenv("LD_ELF_LIBRARY_PATH", envp);
+    if (!_dl_library_path)
+#endif
+      _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+
+    if(!_dl_suid_ok() ) {
+      if (_dl_preload) {
+       *_dl_preload = '\0';
+       _dl_preload = 0;
+      }
+      if (_dl_library_path) {
+       *_dl_library_path = '\0';
+       _dl_library_path = 0;
+      }
+    }
+  }
+
+  _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;
+
+    tcurr = _dl_loaded_modules;
+    if (_dl_preload)  {
+      int i;
+      char *str;
+      char c=1;
+      str = _dl_preload; 
+      for (i = 0; c != 0; i++) {
+       if (_dl_preload[i] == ':' || _dl_preload[i] == '\0') {
+         c= _dl_preload[i];
+         _dl_preload[i]=0;
+         tpnt1 = _dl_load_shared_library(_dl_symbol_tables, 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)
+             _dl_fdprintf(1, "\t%s => %s\n", str, tpnt1->libname);
+           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;
+         }
+         str=_dl_preload+i+1;
+         _dl_preload[i]=c;
+       }
+      }
+    }
+    do{
+      for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+       {
+         if(dpnt->d_tag == DT_NEEDED)
+           {
+             lpnt = tcurr->loadoffs + 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(_dl_symbol_tables, 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\n", lpnt, tpnt1->libname);
+               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;
+             }
+           }
+       }
+      
+      tcurr = tcurr->next;
+    } while(tcurr);
+  }
+
+#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_fixup(_dl_loaded_modules);
+
+  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;
+
+  _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+  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, 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;
+
+  /* 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]) {
+    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);
+  }
+  if(tpnt->dynamic_info[DT_RELA]) {
+    _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+    _dl_exit(18);
+  }
+  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)
+       goof += _dl_parse_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], 1);
+    }
+
+  elf_machine_got_rel(tpnt);
+
+  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_ANON | MAP_COPY, -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 && *pnt1 && *pnt == *pnt1) {pnt1++; pnt++;}
+    if(!*pnt || *pnt != '=' || *pnt1) continue;
+    return pnt+1;
+  }
+  return 0;
+}
+
+char * _dl_strdup(const char * string){
+  void * retval;
+  char * pnt;
+
+  pnt = retval = _dl_malloc_addr;
+  while(*string)
+    *pnt++ = *string++;
+  *pnt++ = 0;
+  _dl_malloc_addr = pnt;
+  /*
+   * 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;
+}
+
+/* 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;
+}
+
+void _dl_printhex(no)
+{
+static char xc[]="0123456789abcdef";
+
+        int i;  
+
+        _dl_write(1, " 0x", 3);
+        for(i=0; i < 8; i++) {
+                _dl_write(1, &xc[((no >> 28) & 0xf)], 1);
+                no <<= 4;
+        }       
+}             
+
diff --git a/gnu/libexec/ld.so/ld.so/hash.c b/gnu/libexec/ld.so/ld.so/hash.c
new file mode 100644 (file)
index 0000000..a7f9a1b
--- /dev/null
@@ -0,0 +1,225 @@
+/* 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
+
+
+/* Various symbol table handling functions, including symbol lookup */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <elf.h>
+
+#include "hash.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 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;
+  tpnt = _dl_loaded_modules;
+  while(tpnt){
+    if(_dl_strcmp(tpnt->libname, libname) == 0) return tpnt;
+    tpnt = tpnt->next;
+  };
+  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,
+                                       char * loadoffs,
+                                       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] + loadoffs);
+    tpnt->nbucket = *hash_addr++;
+    tpnt->nchain = *hash_addr++;
+    tpnt->elf_buckets = hash_addr;
+    hash_addr += tpnt->nbucket;
+    tpnt->chains = hash_addr;
+  }
+  tpnt->loadaddr = loadaddr;
+  tpnt->loadoffs = loadoffs;
+  for(i=0; i<(DT_NUM + DT_MDEP); 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;
+  char * strtab;
+  Elf32_Sym * symtab;
+  unsigned int elf_hash_number, hn;
+  char * weak_result;
+  struct elf_resolve * first_def;
+  struct dyn_elf * rpnt, first;
+
+  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);
+  }
+  
+  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 )
+      {
+       return weak_result;
+      }
+
+    /*
+     * Avoid calling .urem here.
+     */
+    do_rem(hn, elf_hash_number, tpnt->nbucket);
+    symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadoffs);
+    strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadoffs);
+    /*
+     * 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(!first_def) first_def = tpnt;
+       if(f_tpnt && first_def == f_tpnt && symtab[si].st_shndx == 0)
+         continue;
+
+       switch(ELF32_ST_BIND(symtab[si].st_info)){
+       case STB_GLOBAL:
+         return tpnt->loadoffs + symtab[si].st_value;
+       case STB_WEAK:
+         if (!weak_result) weak_result = tpnt->loadoffs + symtab[si].st_value;
+           break;
+       default:  /* Do local symbols need to be examined? */
+         break;
+       }
+      }
+    }
+  }
+  return weak_result;
+}
+
+
diff --git a/gnu/libexec/ld.so/ld.so/hash.h b/gnu/libexec/ld.so/ld.so/hash.h
new file mode 100644 (file)
index 0000000..fea5940
--- /dev/null
@@ -0,0 +1,100 @@
+
+struct dyn_elf{
+  struct elf_resolve * dyn;
+  struct dyn_elf * next_handle;  /* Used by dlopen et al. */
+  struct dyn_elf * next;
+};
+#include <link.h>
+
+#define DT_MDEP         (DT_MIPS_HIPAGENO - DT_LOPROC + 1)
+
+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. */
+  char * loadoffs;
+  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[DT_NUM + DT_MDEP];
+
+  unsigned int dynamic_size;
+  unsigned int n_phent;
+  Elf32_Phdr * ppnt;
+};
+
+#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 elf_resolve * _dl_check_hashed_files(char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, 
+                                              char * loadaddr, 
+                                              char * loadoffs, 
+                                              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 struct elf_resolve * _dl_load_shared_library(struct dyn_elf *,
+                                char * libname);  
+int _dl_copy_fixups(struct dyn_elf * tpnt);
+
+
+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_write(int, const char *, int);
+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/gnu/libexec/ld.so/ld.so/i386/Makefile b/gnu/libexec/ld.so/ld.so/i386/Makefile
new file mode 100644 (file)
index 0000000..6f5ba56
--- /dev/null
@@ -0,0 +1,49 @@
+include ../../Version.mk
+include ../../Config.mk
+
+CC = $(ELFCC)
+AS = $(ELFAS)
+LD = $(ELFLD)
+
+CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops
+
+../%.o: %.S
+       $(CC) $(CFLAGS) -c $< -o $@
+../%.o: %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+SRC1S = resolve.S
+SRC2S = elfinterp.c
+
+SRCS   = $(SRC1S) $(SRC2S)
+OBJ1S  = $(SRC1S:.S=.o)
+OBJ2S  = $(SRC2S:.c=.o)
+OBJS   = $(OBJ1S) $(OBJ2S)
+
+DLINK_OBJS:= $(addprefix ../, $(OBJS))
+
+lib:: $(DLINK_OBJS)
+
+obj: $(DLINK_OBJS)
+
+asm: $(ASMS)
+
+realclean::
+       $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~
+
+clean::
+       $(RM) -f core *.o *.a *.s *.i tmp_make *~
+
+depend::
+       $(CC) $(CFLAGS) -M $(SRCS) | \
+               sed -e 's,^[    ]*\(.*\.o\)[    ]*:,../\1:,' > .depend
+#      $(MAKE) subdir TARGET=depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
diff --git a/gnu/libexec/ld.so/ld.so/i386/elfinterp.c b/gnu/libexec/ld.so/ld.so/i386/elfinterp.c
new file mode 100644 (file)
index 0000000..5db1b46
--- /dev/null
@@ -0,0 +1,328 @@
+/* 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef IBCS_COMPATIBLE
+#include <ibcs/unistd.h>
+#else
+#include <linux/unistd.h>
+#endif
+#include <fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#define SVR4_COMPATIBILITY
+
+extern char *_dl_progname;
+
+extern _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 */
+
+#ifndef BROKEN_LINKER
+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++;
+      };
+    };
+      _dl_memcpy((char *) symtab[symtab_index].st_value, 
+                (char *) symbol_addr, 
+                symtab[symtab_index].st_size);
+  };
+  return goof;
+}
+#endif
+
+
diff --git a/gnu/libexec/ld.so/ld.so/i386/resolve.S b/gnu/libexec/ld.so/ld.so/i386/resolve.S
new file mode 100644 (file)
index 0000000..7236cd7
--- /dev/null
@@ -0,0 +1,51 @@
+#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:
+#ifdef __PIC__
+       pushl %ebx;
+       call    .L26
+.L24:
+       movl RESOLVER@GOT(%ebx),%ebx
+       call *%ebx
+#else
+       call RESOLVER
+#endif
+       popl %ebx
+       addl $8,%esp
+       jmp *%eax
+#ifdef __PIC__
+.L26:
+       popl    %ebx
+       addl    $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
+       jmp     .L24
+#endif
+.LFE2:
+       .size RESOLVE,.LFE2-RESOLVE
diff --git a/gnu/libexec/ld.so/ld.so/i386/string.h b/gnu/libexec/ld.so/ld.so/i386/string.h
new file mode 100644 (file)
index 0000000..f5b3402
--- /dev/null
@@ -0,0 +1,439 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <sys/types.h> /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char * _dl_strcpy(char * dest,const char *src);
+extern inline char * _dl_strncpy(char * dest,const char *src,size_t count);
+extern inline char * _dl_strcat(char * dest,const char * src);
+extern inline char * _dl_strncat(char * dest,const char * src,size_t count);
+extern inline int _dl_strcmp(const char * cs,const char * ct);
+extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count);
+extern inline char * _dl_strchr(const char * s,char c);
+extern inline char * _dl_strrchr(const char * s,char c);
+extern inline size_t _dl_strspn(const char * cs, const char * ct);
+extern inline size_t _dl_strcspn(const char * cs, const char * ct);
+extern inline char * _dl_strpbrk(const char * cs,const char * ct);
+extern inline char * _dl_strstr(const char * cs,const char * ct);
+extern inline size_t _dl_strlen(const char * s);
+extern inline char * _dl_strtok(char * s,const char * ct);
+extern inline void * _dl_memcpy(void * to, const void * from, size_t n);
+extern inline void * _dl_memmove(void * dest,const void * src, size_t n);
+extern inline int _dl_memcmp(const void * cs,const void * ct,size_t count);
+extern inline void * _dl_memchr(const void * cs,char c,size_t count);
+extern inline void * _dl_memset(void * s,char c,size_t count);
+
+/*
+ * This string-include defines all string functions as inline
+ * functions. Use gcc. It also assumes ds=es=data space, this should be
+ * normal. Most of the string-functions are rather heavily hand-optimized,
+ * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ *             Copyright (C) 1991, 1992 Linus Torvalds
+ */
+extern inline char * _dl_strcpy(char * dest,const char *src)
+{
+__asm__("cld\n"
+       "1:\tlodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b"
+       : /* no output */
+       :"S" (src),"D" (dest):"si","di","ax","memory");
+return dest;
+}
+
+extern inline char * _dl_strncpy(char * dest,const char *src,size_t count)
+{
+__asm__("cld\n"
+       "1:\tdecl %2\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n\t"
+       "rep\n\t"
+       "stosb\n"
+       "2:"
+       : /* no output */
+       :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
+return dest;
+}
+
+extern inline char * _dl_strcat(char * dest,const char * src)
+{
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "decl %1\n"
+       "1:\tlodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b"
+       : /* no output */
+       :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+return dest;
+}
+
+extern inline char * _dl_strncat(char * dest,const char * src,size_t count)
+{
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "decl %1\n\t"
+       "movl %4,%3\n"
+       "1:\tdecl %3\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "stosb\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n"
+       "2:\txorl %2,%2\n\t"
+       "stosb"
+       : /* no output */
+       :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
+       :"si","di","ax","cx","memory");
+return dest;
+}
+
+extern inline int _dl_strcmp(const char * cs,const char * ct)
+{
+register int __res;
+__asm__("cld\n"
+       "5:\tlodsb\n\t"
+       "scasb\n\t"
+       "jne 6f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 5b\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "jmp 7f\n"
+       "6:\tmovl $1,%%eax\n\t"
+       "jb 7f\n\t"
+       "negl %%eax\n"
+       "7:"
+       :"=a" (__res):"D" (cs),"S" (ct):"si","di");
+return __res;
+}
+
+extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count)
+{
+register int __res;
+__asm__("cld\n"
+       "1:\tdecl %3\n\t"
+       "js 2f\n\t"
+       "lodsb\n\t"
+       "scasb\n\t"
+       "jne 3f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n"
+       "2:\txorl %%eax,%%eax\n\t"
+       "jmp 4f\n"
+       "3:\tmovl $1,%%eax\n\t"
+       "jb 4f\n\t"
+       "negl %%eax\n"
+       "4:"
+       :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");
+return __res;
+}
+
+extern inline char * _dl_strchr(const char * s,char c)
+{
+register char * __res;
+__asm__("cld\n\t"
+       "movb %%al,%%ah\n"
+       "1:\tlodsb\n\t"
+       "cmpb %%ah,%%al\n\t"
+       "je 2f\n\t"
+       "testb %%al,%%al\n\t"
+       "jne 1b\n\t"
+       "movl $1,%1\n"
+       "2:\tmovl %1,%0\n\t"
+       "decl %0"
+       :"=a" (__res):"S" (s),"0" (c):"si");
+return __res;
+}
+
+extern inline char * _dl_strrchr(const char * s,char c)
+{
+register char * __res;
+__asm__("cld\n\t"
+       "movb %%al,%%ah\n"
+       "1:\tlodsb\n\t"
+       "cmpb %%ah,%%al\n\t"
+       "jne 2f\n\t"
+       "movl %%esi,%0\n\t"
+       "decl %0\n"
+       "2:\ttestb %%al,%%al\n\t"
+       "jne 1b"
+       :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
+return __res;
+}
+
+extern inline size_t _dl_strspn(const char * cs, const char * ct)
+{
+register char * __res;
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 1b\n"
+       "2:\tdecl %0"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline size_t _dl_strcspn(const char * cs, const char * ct)
+{
+register char * __res;
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 1b\n"
+       "2:\tdecl %0"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res-cs;
+}
+
+extern inline char * _dl_strpbrk(const char * cs,const char * ct)
+{
+register char * __res;
+__asm__("cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "movl %%ecx,%%edx\n"
+       "1:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 2f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 1b\n\t"
+       "decl %0\n\t"
+       "jmp 3f\n"
+       "2:\txorl %0,%0\n"
+       "3:"
+       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
+       :"ax","cx","dx","di");
+return __res;
+}
+
+extern inline char * _dl_strstr(const char * cs,const char * ct)
+{
+register char * __res;
+__asm__("cld\n\t" \
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"        /* NOTE! This also sets Z if searchstring='' */
+       "movl %%ecx,%%edx\n"
+       "1:\tmovl %4,%%edi\n\t"
+       "movl %%esi,%%eax\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repe\n\t"
+       "cmpsb\n\t"
+       "je 2f\n\t"             /* also works for empty string, see above */
+       "xchgl %%eax,%%esi\n\t"
+       "incl %%esi\n\t"
+       "cmpb $0,-1(%%eax)\n\t"
+       "jne 1b\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "2:"
+       :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
+       :"cx","dx","di","si");
+return __res;
+}
+
+extern inline size_t _dl_strlen(const char * s)
+{
+register int __res;
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %0\n\t"
+       "decl %0"
+       :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
+return __res;
+}
+
+extern char * ___strtok;
+
+extern inline char * _dl_strtok(char * s,const char * ct)
+{
+register char * __res;
+__asm__("testl %1,%1\n\t"
+       "jne 1f\n\t"
+       "testl %0,%0\n\t"
+       "je 8f\n\t"
+       "movl %0,%1\n"
+       "1:\txorl %0,%0\n\t"
+       "movl $-1,%%ecx\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "cld\n\t"
+       "movl %4,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"
+       "je 7f\n\t"                     /* empty delimeter-string */
+       "movl %%ecx,%%edx\n"
+       "2:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 7f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 2b\n\t"
+       "decl %1\n\t"
+       "cmpb $0,(%1)\n\t"
+       "je 7f\n\t"
+       "movl %1,%0\n"
+       "3:\tlodsb\n\t"
+       "testb %%al,%%al\n\t"
+       "je 5f\n\t"
+       "movl %4,%%edi\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "jne 3b\n\t"
+       "decl %1\n\t"
+       "cmpb $0,(%1)\n\t"
+       "je 5f\n\t"
+       "movb $0,(%1)\n\t"
+       "incl %1\n\t"
+       "jmp 6f\n"
+       "5:\txorl %1,%1\n"
+       "6:\tcmpb $0,(%0)\n\t"
+       "jne 7f\n\t"
+       "xorl %0,%0\n"
+       "7:\ttestl %0,%0\n\t"
+       "jne 8f\n\t"
+       "movl %0,%1\n"
+       "8:"
+       :"=b" (__res),"=S" (___strtok)
+       :"0" (___strtok),"1" (s),"g" (ct)
+       :"ax","cx","dx","di","memory");
+return __res;
+}
+
+extern inline void * _dl_memcpy(void * to, const void * from, size_t n)
+{
+__asm__("cld\n\t"
+       "movl %%edx, %%ecx\n\t"
+       "shrl $2,%%ecx\n\t"
+       "rep ; movsl\n\t"
+       "testb $1,%%dl\n\t"
+       "je 1f\n\t"
+       "movsb\n"
+       "1:\ttestb $2,%%dl\n\t"
+       "je 2f\n\t"
+       "movsw\n"
+       "2:\n"
+       : /* no output */
+       :"d" (n),"D" ((long) to),"S" ((long) from)
+       : "cx","di","si","memory");
+return (to);
+}
+
+extern inline void * _dl_memmove(void * dest,const void * src, size_t n)
+{
+if (dest<src)
+__asm__("cld\n\t"
+       "rep\n\t"
+       "movsb"
+       : /* no output */
+       :"c" (n),"S" (src),"D" (dest)
+       :"cx","si","di");
+else
+__asm__("std\n\t"
+       "rep\n\t"
+       "movsb\n\t"
+       "cld"
+       : /* no output */
+       :"c" (n),
+        "S" (n-1+(const char *)src),
+        "D" (n-1+(char *)dest)
+       :"cx","si","di","memory");
+return dest;
+}
+
+extern inline int _dl_memcmp(const void * cs,const void * ct,size_t count)
+{
+register int __res;
+__asm__("cld\n\t"
+       "repe\n\t"
+       "cmpsb\n\t"
+       "je 1f\n\t"
+       "movl $1,%%eax\n\t"
+       "jb 1f\n\t"
+       "negl %%eax\n"
+       "1:"
+       :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)
+       :"si","di","cx");
+return __res;
+}
+
+extern inline void * _dl_memchr(const void * cs,char c,size_t count)
+{
+register void * __res;
+if (!count)
+       return NULL;
+__asm__("cld\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "je 1f\n\t"
+       "movl $1,%0\n"
+       "1:\tdecl %0"
+       :"=D" (__res):"a" (c),"D" (cs),"c" (count)
+       :"cx");
+return __res;
+}
+
+extern inline void * _dl_memset(void * s,char c,size_t count)
+{
+__asm__("cld\n\t"
+       "rep\n\t"
+       "stosb"
+       : /* no output */
+       :"a" (c),"D" (s),"c" (count)
+       :"cx","di","memory");
+return s;
+}
+
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/i386/syscall.h b/gnu/libexec/ld.so/ld.so/i386/syscall.h
new file mode 100644 (file)
index 0000000..21fe6ac
--- /dev/null
@@ -0,0 +1,281 @@
+
+extern inline volatile void _dl_exit(int status);
+extern inline volatile void _dl_close(int fd);
+extern inline int _dl_mmap(void * addr, unsigned int size,
+                                   unsigned int prot,
+                                   unsigned int flags, int fd,
+                                   unsigned int f_offset);
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+#define _dl_mmap_check_error(__res)    \
+       (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+extern inline int _dl_open(char * addr, unsigned int flags);
+extern inline int _dl_write(int fd, const char * buf, int len);
+extern inline int _dl_read(int fd, const char * buf, int len);
+extern inline int _dl_mprotect(const char * addr, int size, int prot);
+#include <sys/stat.h>
+extern inline int _dl_stat(char * filename, struct stat *st);
+extern inline int _dl_munmap(char * addr, int size);
+
+/* Here are the definitions for a bunch of syscalls that are required
+   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. */
+
+extern inline volatile void _dl_exit(int status)
+{
+  int __res;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %0\n\tpushl $0\n\tmovl %1,%%eax\n\t" \
+                   "lcall $7,$0" : : "r" (status), "a" (__IBCS_exit));
+#else
+  __asm__ volatile ("movl %%ecx,%%ebx\n"\
+                   "int $0x80" \
+                   :  "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
+#endif
+}
+
+extern inline volatile void _dl_close(int fd)
+{
+    int status;
+
+#ifdef IBCS_COMPATIBLE
+    __asm__ volatile ("pushl %1\n\t" \
+           "pushl $0\n\t" \
+           "movl %2,%%eax\n\t" \
+           "lcall $7,$0\n\t" \
+           "jnb .+4\n\t" \
+           "xor %%eax, %%eax\n\t" \
+           "addl $8,%%esp\n\t" \
+           : "=a" (status) : "r" (fd), "a" (__IBCS_close));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%ecx,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (status) \
+                   : "0" (__NR_close),"c" ((long)(fd)));
+    
+#endif
+}
+
+extern inline int _dl_mmap(void * addr, unsigned int size,
+                                   unsigned int prot,
+                                   unsigned int flags, int fd,
+                                   unsigned int f_offset)
+{
+  int malloc_buffer;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %7\n\t" \
+                   "pushl %6\n\t" \
+                   "pushl %5\n\t" \
+                   "pushl %4\n\t" \
+                   "pushl %3\n\t" \
+                   "pushl %2\n\t" \
+                   "pushl $0\n\t" \
+                   "movl %1,%%eax\n\t" \
+                   "lcall $7,$0\n\t" \
+                   "jnb .+4\n\t" \
+                   "xor %%eax, %%eax\n\t" \
+                   "addl $28,%%esp\n\t" \
+                   : "=a" (malloc_buffer) : "a" (__IBCS_mmap),
+                   "rm" (addr), "rm" (size), "rm" (prot), "rm" (flags), 
+                   "rm" (fd), "rm" (f_offset));
+#else
+  __asm__ volatile ("pushl %%ebx\n\t" \
+                   "pushl %7\n\t" \
+                   "pushl %6\n\t" \
+                   "pushl %5\n\t" \
+                   "pushl %4\n\t" \
+                   "pushl %3\n\t" \
+                   "pushl %2\n\t" \
+                   "movl %%esp,%%ebx\n\t" \
+                   "int $0x80\n\t" \
+                   "addl $24,%%esp\n\t" \
+                   "popl %%ebx\n" \
+                   : "=a" (malloc_buffer) : "a" (__NR_mmap),
+                   "rm" (addr), "rm" (size), "rm" (prot), "rm" (flags), 
+                   "rm" (fd), "rm" (f_offset));
+#endif
+  return malloc_buffer;
+}
+
+
+extern inline int _dl_open(char * addr, unsigned int flags)
+{
+  int zfileno;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %3\n\t" \
+           "pushl %2\n\t" \
+           "pushl $0\n\t" \
+           "movl %1,%%eax\n\t" \
+           "lcall $7,$0\n\t" \
+           "jnb .+7\n\t" \
+           "movl $-1, %%eax\n\t" \
+           "addl $12,%%esp\n\t" \
+           :"=a" (zfileno) : "i" (__IBCS_open), "rm" (addr), "rm" (flags));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%esi,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (zfileno) \
+                   : "0" (__NR_open),"S" ((long)(addr)),"c" ((long)(flags)));
+#endif
+
+  return zfileno;
+}
+
+extern inline int _dl_write(int fd, const char * buf, int len)
+{
+  int status;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %4\n\t" \
+         "pushl %3\n\t" \
+         "pushl %2\n\t" \
+         "pushl $0\n\t" \
+         "movl %1,%%eax\n\t" \
+         "lcall $7,$0\n\t" \
+         "jnb .+4\n\t" \
+         "xor %%eax, %%eax\n\t" \
+         "addl $12,%%esp\n\t" \
+         :"=a" (status) : "i" (__IBCS_write), "rm" (fd), "rm" (buf), "rm" (len));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%esi,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (status) \
+                   : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
+#endif
+}
+
+
+extern inline int _dl_read(int fd, const char * buf, int len)
+{
+  int status;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %4\n\t" \
+         "pushl %3\n\t" \
+         "pushl %2\n\t" \
+         "pushl $0\n\t" \
+         "movl %1,%%eax\n\t" \
+         "lcall $7,$0\n\t" \
+         "jnb .+4\n\t" \
+         "xor %%eax, %%eax\n\t" \
+         "addl $12,%%esp\n\t" \
+         : "=a" (status) : "i" (__IBCS_read), "rm" (fd), "rm" (buf), "rm" (len));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%esi,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (status) \
+                   : "0" (__NR_read),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
+#endif
+}
+
+extern inline int _dl_mprotect(const char * addr, int size, int prot)
+{
+  int status;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %4\n\t" \
+         "pushl %3\n\t" \
+         "pushl %2\n\t" \
+         "pushl $0\n\t" \
+         "movl %1,%%eax\n\t" \
+         "lcall $7,$0\n\t" \
+         "jnb .+7\n\t" \
+         "movl $-1, %%eax\n\t" \
+         "addl $16,%%esp\n\t" \
+         :"=a" (status) : "i" (__IBCS_mprotect), "rm" (addr), "rm" (size), "rm" (prot));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%esi,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (status) \
+                   : "0" (__NR_mprotect),"S" ((long)(addr)),"c" ((long)(size)),"d" ((long)(prot)));
+#endif
+  return status;
+}
+
+extern inline int _dl_stat(char * filename, struct stat *st)
+{
+  int ret;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %3\n\t" \
+            "pushl %2\n\t" \
+            "pushl $0\n\t" \
+            "movl %1,%%eax\n\t" \
+            "lcall $7,$0\n\t" \
+            "jnb .+7\n\t" \
+            "movl $-1, %%eax\n\t" \
+            "addl $12,%%esp\n\t" \
+            :"=a" (ret) : "i" (__IBCS_stat), "rm" (filename), "rm" (st));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                    "movl %%esi,%%ebx\n"\
+                    "int $0x80\n" \
+                    "popl %%ebx\n"\
+                    : "=a" (ret) \
+                    : "0" (__NR_stat),"S" (filename),"c" (st));
+#endif
+
+  return ret;
+}
+
+extern inline int _dl_munmap(char * addr, int size)
+{
+  int ret;
+#ifdef IBCS_COMPATIBLE
+  __asm__ volatile ("pushl %3\n\t" \
+           "pushl %2\n\t" \
+           "pushl $0\n\t" \
+           "movl %1,%%eax\n\t" \
+           "lcall $7,$0\n\t" \
+           "jnb .+7\n\t" \
+           "movl $-1, %%eax\n\t" \
+           "addl $12,%%esp\n\t" \
+           :"=a" (ret) : "i" (__IBCS_munmap), "rm" (addr), "rm" (size));
+#else
+  __asm__ volatile ("pushl %%ebx\n"\
+                   "movl %%esi,%%ebx\n"\
+                   "int $0x80\n" \
+                   "popl %%ebx\n"\
+                   : "=a" (ret) \
+                   : "0" (__NR_munmap),"S" ((long)(addr)),"c" ((long)(size)));
+#endif
+
+  return ret;
+}
+
+/*
+ * 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)
+{
+  unsigned int uid, euid, gid, egid;
+  euid = egid = 0; /* So compiler does not warn us */
+
+#ifdef IBCS_COMPATIBLE
+    __asm__("movl %2,%%eax\n\tlcall $7,$0" :"=a" (uid), "=d" (euid) :"a" (__IBCS_getuid));
+    __asm__("movl %2,%%eax\n\tlcall $7,$0" :"=a" (gid), "=d" (egid) :"a" (__IBCS_getgid));
+#else
+    __asm__ volatile ("int $0x80" : "=a" (uid) : "0" (__NR_getuid));
+    __asm__ volatile ("int $0x80" : "=a" (euid) : "0" (__NR_geteuid));
+    __asm__ volatile ("int $0x80" : "=a" (gid) : "0" (__NR_getgid));
+    __asm__ volatile ("int $0x80" : "=a" (egid) : "0" (__NR_getegid));
+#endif
+
+    if(uid == euid && gid == egid)
+      return 1;
+    else
+      return 0;
+}
+
diff --git a/gnu/libexec/ld.so/ld.so/i386/sysdep.h b/gnu/libexec/ld.so/ld.so/i386/sysdep.h
new file mode 100644 (file)
index 0000000..09eeb4b
--- /dev/null
@@ -0,0 +1,90 @@
+
+/*
+ * 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 this because we do not want to call .udiv in the library.
+ */
+#define do_div(n,base) ({ \
+int __res; \
+__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
+__res; })
+
+#define do_rem(result, n, base)  result = (n % base)
diff --git a/gnu/libexec/ld.so/ld.so/ld.so.8 b/gnu/libexec/ld.so/ld.so/ld.so.8
new file mode 100644 (file)
index 0000000..19bd563
--- /dev/null
@@ -0,0 +1,172 @@
+.TH ld.so 8 "30 March 1995"
+.SH NAME
+ld.so \- a.out dynamic linker/loader
+.SH DESCRIPTION
+.B ld.so
+completes the final process of linking all necessary references to 
+sharable objects and unreferenced symbols in an impure executable,
+(usually a 
+.I dynamically
+.I linked
+.IR executable ),
+to produce a runnable file.
+.PP
+Unless explicitly specified via the
+.B \-static
+option to
+.B ld
+during compilation, all Linux binaries in a.out format will be "incomplete"
+and require further linking at run time.
+.BR ld.so 's
+job is thus to complete the linking process started at compilation.
+.PP
+The necessary dynamically linked libraries (DLL's) which the executable
+requires to complete it's linking process are searched for in the following
+order
+.IP o
+Using the environment variable
+.BR LD_AOUT_LIBRARY_PATH .
+Except if the executable is a setuid/setgid binary, in which case it
+is ignored.
+.IP o
+Using the environment variable
+.BR LD_LIBRARY_PATH .
+Except if
+.B LD_AOUT_LIBRARY_PATH
+is specified or 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 MESSAGES
+The following, possibly fatal, warnings may be output by
+.B ld.so
+.TP
+.SB can't find library 'libfoo'
+If
+.B ld.so
+cannot find the library the executable requires anywhere.
+.TP
+.SB can't load library 'libfoo'
+If the library is corrupt.
+.TP
+.SB incompatible library 'libfoo'
+.PD 0
+.TP
+.SB Require major version x and found y
+.PD
+.B ld.so
+cannot use the library version found as it is incompatable with the
+binary attempting to be executed.
+.TP
+.SB using incompatible library 'libfoo'
+.PD 0
+.TP
+.SB Desire minor version >= x and found y
+.PD
+Even though the minor version is incompatable
+.B ld.so
+will attempt to use it.
+This message is suppressed if the environment variable
+.B LD_NOWARN
+is set.
+.TP
+.SB too many directories in library path
+There is a hard coded limit of 32 search directories. The above warning will
+ensue it this limit is exceeded.
+.TP
+.SB dynamic linker error in fixup pass 1,2
+.PD 0
+.TP
+.SB dynamic linker error in resolve pass
+.TP
+.SB dynamic linker error in reset pass
+.PD
+An attempt to perform necessary fixups and or relocations failed. These are
+usually fatal and signifies possible binary corruption.
+.TP
+.SB can't map cache file '/etc/ld.so.cache'
+.PD 0
+.TP
+.SB cache file '/etc/ld.so.cache' is corrupt
+.TP
+.SB cache file '/etc/ld.so.cache' has wrong version
+.TP
+.SB cache file '/etc/ld.so.cache' is empty
+.PD
+A problem was encountered with the cache.
+Execution will continue as if the cache did not exist.
+.SH ENVIRONMENT
+.TP
+.B LD_AOUT_LIBRARY_PATH
+A colon-separated list of directories in which to search for
+libraries at execution-time.
+Similar to the 
+.B PATH
+environment variable.
+.TP
+.B LD_LIBRARY_PATH
+A colon-separated list of directories in which to search for
+libraries at execution-time if
+.B LD_AOUT_LIBRARY_PATH
+is not specified.
+Similar to the 
+.B PATH
+environment variable.
+.TP
+.B LD_NOWARN
+Suppress warnings about libraries with incompatible minor version numbers.
+.TP
+.B LD_KEEPDIR
+Don't ignore the directory in the names of libraries to be loaded.
+Use of this option is strongly discouraged.
+.TP
+.B LD_AOUT_PRELOAD
+The name of an additional, user-specified, shared library to be loaded 
+after all others.
+This can be used to selectively override functions in other shared libraries.
+.B LD_PRELOAD
+The name of an additional, user-specified, shared library to be loaded 
+after all others if
+.B LD_AOUT_PRELOAD
+is not specified.
+This can be used to selectively override functions in other shared libraries.
+.SH FILES
+.PD 0
+.TP 20
+.B /lib/ld.so
+execution time 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 lib*.so.version
+shared libraries
+.TP
+.B lib*.sa
+exported initialized library data.
+.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 compatable 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/gnu/libexec/ld.so/ld.so/m68k/Makefile b/gnu/libexec/ld.so/ld.so/m68k/Makefile
new file mode 100644 (file)
index 0000000..6f5ba56
--- /dev/null
@@ -0,0 +1,49 @@
+include ../../Version.mk
+include ../../Config.mk
+
+CC = $(ELFCC)
+AS = $(ELFAS)
+LD = $(ELFLD)
+
+CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops
+
+../%.o: %.S
+       $(CC) $(CFLAGS) -c $< -o $@
+../%.o: %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+SRC1S = resolve.S
+SRC2S = elfinterp.c
+
+SRCS   = $(SRC1S) $(SRC2S)
+OBJ1S  = $(SRC1S:.S=.o)
+OBJ2S  = $(SRC2S:.c=.o)
+OBJS   = $(OBJ1S) $(OBJ2S)
+
+DLINK_OBJS:= $(addprefix ../, $(OBJS))
+
+lib:: $(DLINK_OBJS)
+
+obj: $(DLINK_OBJS)
+
+asm: $(ASMS)
+
+realclean::
+       $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~
+
+clean::
+       $(RM) -f core *.o *.a *.s *.i tmp_make *~
+
+depend::
+       $(CC) $(CFLAGS) -M $(SRCS) | \
+               sed -e 's,^[    ]*\(.*\.o\)[    ]*:,../\1:,' > .depend
+#      $(MAKE) subdir TARGET=depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
diff --git a/gnu/libexec/ld.so/ld.so/m68k/elfinterp.c b/gnu/libexec/ld.so/ld.so/m68k/elfinterp.c
new file mode 100644 (file)
index 0000000..e41174b
--- /dev/null
@@ -0,0 +1,360 @@
+/* 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef IBCS_COMPATIBLE
+#include <ibcs/unistd.h>
+#else
+#include <linux/unistd.h>
+#endif
+#include <fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "sysdep.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 + rpnt->r_addend;
+         break;
+       case R_68K_RELATIVE:
+         *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
+         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.  */
+
+#ifndef BROKEN_LINKER
+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++;
+           }
+       }
+      _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
+                 symtab[symtab_index].st_size);
+    }
+  return goof;
+}
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/m68k/resolve.S b/gnu/libexec/ld.so/ld.so/m68k/resolve.S
new file mode 100644 (file)
index 0000000..7d0be19
--- /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
+       jsr     __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/gnu/libexec/ld.so/ld.so/m68k/string.h b/gnu/libexec/ld.so/ld.so/m68k/string.h
new file mode 100644 (file)
index 0000000..5267721
--- /dev/null
@@ -0,0 +1,303 @@
+#ifndef _DL_STRING_H_
+#define _DL_STRING_H_
+
+#include <linux/types.h>       /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char *_dl_strcpy (char *dest, const char *src);
+extern inline char *_dl_strncpy (char *dest, const char *src, size_t count);
+extern inline char *_dl_strcat (char *dest, const char *src);
+extern inline char *_dl_strncat (char *dest, const char *src, size_t count);
+extern inline int _dl_strcmp (const char *cs, const char *ct);
+extern inline int _dl_strncmp (const char *cs, const char *ct, size_t count);
+extern inline char *_dl_strchr (const char *s, int c);
+extern inline char *_dl_strrchr (const char *s, int c);
+extern inline size_t _dl_strspn (const char *cs, const char *ct);
+extern inline size_t _dl_strcspn (const char *cs, const char *ct);
+extern inline char *_dl_strpbrk (const char *cs, const char *ct);
+extern inline char *_dl_strstr (const char *cs, const char *ct);
+extern inline size_t _dl_strlen (const char *s);
+extern inline char *_dl_strtok (char *s, const char *ct);
+extern inline void *_dl_memcpy (void *to, const void *from, size_t n);
+extern inline void *_dl_memmove (void *dest, const void *src, size_t n);
+extern inline int _dl_memcmp (const void *cs, const void *ct, size_t count);
+extern inline void *_dl_memchr (const void *cs, int c, size_t count);
+extern inline void *_dl_memset (void *s, int c, size_t count);
+
+/* Make sure we are using our inline version.  */
+#define strlen(s) _dl_strlen(s)
+
+extern inline char *
+_dl_strcpy (char *dest, const char *src)
+{
+  char *xdest = dest;
+
+  while ((*dest++ = *src++) != '\0')
+    ;
+  return xdest;
+}
+
+extern inline char *
+_dl_strncpy (char *dest, const char *src, size_t n)
+{
+  char *xdest = dest;
+
+  if (n == 0)
+    return xdest;
+
+  while ((*dest = *src++) != '\0')
+    if (--n == 0)
+      break;
+  return xdest;
+}
+
+extern inline char *
+_dl_strcat (char *dest, const char *src)
+{
+  char *xdest = dest;
+
+  while (*dest)
+    dest++;
+  while ((*dest++ = *src++) != '\0')
+    ;
+
+  return xdest;
+}
+
+extern inline char *
+_dl_strncat (char *dest, const char *src, size_t count)
+{
+  char *xdest = dest;
+
+  if (count)
+    {
+      while (*dest)
+       dest++;
+      while ((*dest++ = *src++) != '\0')
+       if (--count == 0)
+         break;
+    }
+
+  return xdest;
+}
+
+extern inline int
+_dl_strcmp (const char *cs, const char *ct)
+{
+  char c;
+
+  while ((c = *cs++) == *ct++)
+    if (c == 0)
+      return 0;
+  return c - *--ct;
+}
+
+extern inline int
+_dl_strncmp (const char *cs, const char *ct, size_t count)
+{
+  char c;
+
+  if (!count)
+    return 0;
+
+  while ((c = *cs++) == *ct++)
+    if (c == 0 || --count == 0)
+      return 0;
+  return c - *--ct;
+}
+
+extern inline char *
+_dl_strchr (const char *s, int c)
+{
+  const char ch = c;
+
+  for (; *s != ch; ++s)
+    if (*s == '\0')
+      return NULL;
+  return (char *) s;
+}
+
+extern inline char *
+_dl_strrchr (const char * s, int c)
+{
+  char *res = NULL;
+  const char ch = c;
+
+  for (;; ++s)
+    {
+      if (*s == ch)
+       res = (char *) s;
+      if (*s == '\0')
+       break;
+    }
+  return res;
+}
+
+extern inline size_t
+_dl_strspn (const char *s, const char *accept)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = accept; *a != '\0'; ++a)
+       if (*p == *a)
+         break;
+      if (*a == '\0')
+       return count;
+      ++count;
+    }
+
+  return count;
+}
+
+extern inline size_t
+_dl_strcspn (const char *s, const char *reject)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = reject; *a != '\0'; ++a)
+       if (*p == *a)
+         return count;
+      ++count;
+    }
+
+  return count;
+}
+
+extern inline char *
+_dl_strpbrk (const char *cs, const char *ct)
+{
+  const char *sc1, *sc2;
+
+  for (sc1 = cs; *sc1 != '\0'; ++sc1)
+    for (sc2 = ct; *sc2 != '\0'; ++sc2)
+      if (*sc1 == *sc2)
+       return (char *) sc1;
+  return NULL;
+}
+
+extern inline char *
+_dl_strstr (const char *cs, const char *ct)
+{
+  const char *p;
+
+  for (;; cs++)
+    {
+      for (p = ct; *p == *cs; p++, cs++)
+       if (*p == 0)
+         return (char *) cs - (p - ct);
+      cs -= p - ct;
+      if (*cs == 0)
+       return NULL;
+    }
+}
+
+extern inline size_t
+_dl_strlen (const char *s)
+{
+  const char *sc;
+
+  for (sc = s; *sc != '\0'; ++sc)
+    ;
+  return sc - s;
+}
+
+extern char * ___strtok;
+
+extern inline char *
+_dl_strtok(char * s,const char * ct)
+{
+  char *sbegin, *send;
+
+  sbegin = s ? s : ___strtok;
+  if (!sbegin)
+    return NULL;
+  sbegin += _dl_strspn (sbegin, ct);
+  if (*sbegin == '\0')
+    {
+      ___strtok = NULL;
+      return NULL;
+    }
+  send = _dl_strpbrk (sbegin, ct);
+  if (send && *send != '\0')
+    *send++ = '\0';
+  ___strtok = send;
+  return sbegin;
+}
+
+extern inline void *
+_dl_memcpy (void *to, const void *from, size_t n)
+{
+  char *cto = to;
+  const char *cfrom = from;
+
+  while (n--)
+    *cto++ = *cfrom++;
+  return to;
+}
+
+extern inline void *
+_dl_memmove (void *dest, const void *src, size_t n)
+{
+  char *cdest = dest;
+  const char *csrc = src;
+
+  if (dest < src)
+    {
+      while (n--)
+       *cdest++ = *csrc++;
+    }
+  else
+    {
+      cdest += n;
+      csrc += n;
+      while (n--)
+       *--cdest = *--csrc;
+    }
+  return dest;
+}
+
+extern inline int
+_dl_memcmp (const void *cs, const void *ct, size_t count)
+{
+  const unsigned char *su1, *su2;
+
+  for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
+    if (*su1 != *su2)
+      return *su1 < *su2 ? -1 : 1;
+  return 0;
+}
+
+extern inline void *
+_dl_memchr (const void *cs, int c, size_t count)
+{
+  const unsigned char ch = c;
+  const unsigned char *s = cs;
+
+  for (; count != 0; ++s, count--)
+    if (*s == ch)
+      return (void *) s;
+  return NULL;
+}
+
+extern inline void *
+_dl_memset (void *s, int c, size_t count)
+{
+  char *cs = s;
+
+  while (count--)
+    *cs++ = c;
+  return s;
+}
+
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/m68k/syscall.h b/gnu/libexec/ld.so/ld.so/m68k/syscall.h
new file mode 100644 (file)
index 0000000..c5f15e3
--- /dev/null
@@ -0,0 +1,182 @@
+#ifdef USE_CACHE
+#include <sys/stat.h>
+#endif
+
+extern inline void _dl_exit (int status) __attribute__ ((noreturn));
+extern inline int _dl_close (int fd);
+extern inline int _dl_mmap (void *addr, unsigned int size,
+                           unsigned int prot,
+                           unsigned int flags, int fd,
+                           unsigned int f_offset);
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+#define _dl_mmap_check_error(__res)    \
+  ((int) __res < 0 && (int) __res >= -_dl_MAX_ERRNO)
+extern inline int _dl_open (const char *addr, unsigned int flags);
+extern inline int _dl_write (int fd, const char *buf, int len);
+extern inline int _dl_read (int fd, char *buf, int len);
+extern inline int _dl_mprotect (const void *addr, int size, int prot);
+#ifdef USE_CACHE
+extern inline int _dl_stat (const char *, struct stat *);
+extern inline int _dl_munmap (const void *, unsigned int);
+#endif
+
+/* Here are the definitions for a bunch of syscalls that are required
+   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. */
+
+extern inline void
+_dl_exit (int status)
+{
+  register int __res __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n"
+                   "trap #0"
+                   : "=d" (__res)
+                   : "0" (__NR_exit), "d" (status)
+                   : "%d0", "%d1");
+  for (;;);
+}
+
+extern inline int
+_dl_close (int fd)
+{
+  register int status __asm__ ("%d0");
+
+  __asm__ volatile ("movel %2,%/d1\n"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_close), "d" (fd)
+                   : "%d0", "%d1");
+  return status;
+}
+
+extern inline int
+_dl_mmap (void *addr, unsigned int size, unsigned int prot,
+         unsigned int flags, int fd, unsigned int f_offset)
+{
+  register int malloc_buffer __asm__ ("%d0");
+  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) f_offset;
+  
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "trap #0"
+                   : "=d" (malloc_buffer)
+                   : "0" (__NR_mmap), "g" (buffer)
+                   : "%d0", "%d1");
+  return malloc_buffer;
+}
+
+
+extern inline int
+_dl_open (const char *addr, unsigned int flags)
+{
+  register int zfileno __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "trap #0"
+                   : "=d" (zfileno)
+                   : "0" (__NR_open), "g" (addr), "g" (flags)
+                   : "%d0", "%d1", "%d2");
+  return zfileno;
+}
+
+extern inline int
+_dl_write (int fd, const char* buf, int len)
+{
+  register int status __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "movel %4,%/d3\n\t"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_write), "g" (fd), "g" (buf), "g" (len)
+                   : "%d0", "%d1", "%d2", "%d3");
+  return status;
+}
+
+
+extern inline int
+_dl_read (int fd, char *buf, int len)
+{
+  register int status __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "movel %4,%/d3\n\t"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_read), "g" (fd), "g" (buf), "g" (len)
+                   : "%d0", "%d1", "%d2", "%d3");
+  return status;
+}
+
+extern inline int
+_dl_mprotect (const void *addr, int size, int prot)
+{
+  register int status __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "movel %4,%/d3\n\t"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_mprotect), "g" (addr), "g" (size), "g" (prot)
+                   : "%d0", "%d1", "%d2", "%d3");
+  return status;
+}
+
+#ifdef USE_CACHE
+extern inline int
+_dl_stat (const char *name, struct stat *sb)
+{
+  register int status __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_stat), "g" (name), "g" (sb)
+                   : "%d0", "%d1", "%d2");
+  return status;
+}
+
+extern inline int
+_dl_munmap (const void *addr, unsigned int size)
+{
+  register int status __asm__ ("%d0");
+  __asm__ volatile ("movel %2,%/d1\n\t"
+                   "movel %3,%/d2\n\t"
+                   "trap #0"
+                   : "=d" (status)
+                   : "0" (__NR_munmap), "g" (addr), "g" (size)
+                   : "%d0", "%d1");
+  return status;
+}
+#endif
+
+/* 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)
+{
+  unsigned int uid, euid, gid, egid;
+
+  __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0"
+                   : "=g" (uid) : "i" (__NR_getuid) : "%d0");
+  __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0"
+                   : "=g" (euid) : "i" (__NR_geteuid) : "%d0");
+  __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0"
+                   : "=g" (gid) : "i" (__NR_getgid) : "%d0");
+  __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0"
+                   : "=g" (egid) : "i" (__NR_getegid) : "%d0");
+
+  return (uid == euid && gid == egid);
+}
diff --git a/gnu/libexec/ld.so/ld.so/m68k/sysdep.h b/gnu/libexec/ld.so/ld.so/m68k/sysdep.h
new file mode 100644 (file)
index 0000000..b69bab2
--- /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) + (RELP)->r_addend;                    \
+      break;                                                   \
+    case R_68K_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.  */
+
+#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/gnu/libexec/ld.so/ld.so/mips/Makefile b/gnu/libexec/ld.so/ld.so/mips/Makefile
new file mode 100644 (file)
index 0000000..b46abb0
--- /dev/null
@@ -0,0 +1,49 @@
+.include "../../Version.mk"
+.include "../../Config.mk"
+
+CC = $(ELFCC)
+AS = $(ELFAS)
+LD = $(ELFLD)
+
+CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -mabicalls -G0 -fPIC -D__PIC__ #-DDEBUG # -funroll-loops
+
+../%.o: %.S
+       $(CC) $(CFLAGS) -c $< -o $@
+../%.o: %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+SRC1S = resolve.S
+SRC2S = elfinterp.c
+
+SRCS   = $(SRC1S) $(SRC2S)
+OBJ1S  = $(SRC1S:.S=.o)
+OBJ2S  = $(SRC2S:.c=.o)
+OBJS   = $(OBJ1S) $(OBJ2S)
+
+DLINK_OBJS:= $(addprefix ../, $(OBJS))
+
+lib:: $(DLINK_OBJS)
+
+obj: $(DLINK_OBJS)
+
+asm: $(ASMS)
+
+realclean::
+       $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~
+
+clean::
+       $(RM) -f core *.o *.a *.s *.i tmp_make *~
+
+depend::
+       $(CC) $(CFLAGS) -M $(SRCS) | \
+               sed -e 's,^[    ]*\(.*\.o\)[    ]*:,../\1:,' > .depend
+#      $(MAKE) subdir TARGET=depend
+
+#
+# include a dependency file if one exists
+#
+#ifeq (.depend,$(wildcard .depend))
+#include .depend
+#endif
+
diff --git a/gnu/libexec/ld.so/ld.so/mips/elf-machine.h b/gnu/libexec/ld.so/ld.so/mips/elf-machine.h
new file mode 100644 (file)
index 0000000..b44b64d
--- /dev/null
@@ -0,0 +1,27 @@
+/* This file defines MIPS specific ELF types, structures, and macros.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _ELF_MIPS_H
+#define        _ELF_MIPS_H 1
+
+#define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
+#define DT_PROCNUM (DT_MIPS_HIPAGENO - DT_LOPROC + 1)
+
+
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/mips/elf.h b/gnu/libexec/ld.so/ld.so/mips/elf.h
new file mode 100644 (file)
index 0000000..03c1519
--- /dev/null
@@ -0,0 +1,610 @@
+/* This file defines standard ELF types, structures, and macros.
+Copyright (C) 1995 Free Software Foundation, Inc.
+Contributed by Ian Lance Taylor (ian@cygnus.com).
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _ELF_H
+#define        _ELF_H 1
+
+
+/* Standard ELF types.
+
+   Using __attribute__ mode ensures that gcc will choose the right for
+   these types.  */
+
+typedef unsigned int Elf32_Addr    __attribute__ ((mode (SI)));
+typedef unsigned int Elf32_Half    __attribute__ ((mode (HI)));
+typedef unsigned int Elf32_Off     __attribute__ ((mode (SI)));
+typedef                 int Elf32_Sword   __attribute__ ((mode (SI)));
+typedef unsigned int Elf32_Word    __attribute__ ((mode (SI)));
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf32_Half   e_type;                 /* Object file type */
+  Elf32_Half   e_machine;              /* Architecture */
+  Elf32_Word   e_version;              /* Object file version */
+  Elf32_Addr   e_entry;                /* Entry point virtual address */
+  Elf32_Off    e_phoff;                /* Program header table file offset */
+  Elf32_Off    e_shoff;                /* Section header table file offset */
+  Elf32_Word   e_flags;                /* Processor-specific flags */
+  Elf32_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf32_Half   e_phentsize;            /* Program header table entry size */
+  Elf32_Half   e_phnum;                /* Program header table entry count */
+  Elf32_Half   e_shentsize;            /* Section header table entry size */
+  Elf32_Half   e_shnum;                /* Section header table entry count */
+  Elf32_Half   e_shstrndx;             /* Section header string table index */
+} Elf32_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0                0               /* File identification byte 0 index */
+#define ELFMAG0                0x7f            /* Magic number byte 0 */
+
+#define EI_MAG1                1               /* File identification byte 1 index */
+#define ELFMAG1                'E'             /* Magic number byte 1 */
+
+#define EI_MAG2                2               /* File identification byte 2 index */
+#define ELFMAG2                'L'             /* Magic number byte 2 */
+
+#define EI_MAG3                3               /* File identification byte 3 index */
+#define ELFMAG3                'F'             /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define        ELFMAG          "\177ELF"
+#define        SELFMAG         4
+
+#define EI_CLASS       4               /* File class byte index */
+#define ELFCLASSNONE   0               /* Invalid class */
+#define ELFCLASS32     1               /* 32-bit objects */
+#define ELFCLASS64     2               /* 64-bit objects */
+
+#define EI_DATA                5               /* Data encoding byte index */
+#define ELFDATANONE    0               /* Invalid data encoding */
+#define ELFDATA2LSB    1               /* 2's complement, little endian */
+#define ELFDATA2MSB    2               /* 2's complement, big endian */
+
+#define EI_VERSION     6               /* File version byte index */
+                                       /* Value must be EV_CURRENT */
+
+#define EI_PAD         7               /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE                0               /* No file type */
+#define ET_REL         1               /* Relocatable file */
+#define ET_EXEC                2               /* Executable file */
+#define ET_DYN         3               /* Shared object file */
+#define ET_CORE                4               /* Core file */
+#define        ET_NUM          5               /* Number of defined types.  */
+#define ET_LOPROC      0xff00          /* Processor-specific */
+#define ET_HIPROC      0xffff          /* Processor-specific */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE                0               /* No machine */
+#define EM_M32         1               /* AT&T WE 32100 */
+#define EM_SPARC       2               /* SUN SPARC */
+#define EM_386         3               /* Intel 80386 */
+#define EM_68K         4               /* Motorola m68k family */
+#define EM_88K         5               /* Motorola m88k family */
+#define EM_486         6               /* Intel 80486 */
+#define EM_860         7               /* Intel 80860 */
+#define EM_MIPS                8               /* MIPS R3000 big-endian */
+#define EM_S370                9               /* Amdahl */
+#define EM_MIPS_RS4_BE 10              /* MIPS R4000 big-endian */
+
+#define EM_SPARC64     11              /* SPARC v9 (not official) 64-bit */
+
+#define EM_PARISC      15              /* HPPA */
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE                0               /* Invalid ELF version */
+#define EV_CURRENT     1               /* Current version */
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word   sh_name;                /* Section name (string tbl index) */
+  Elf32_Word   sh_type;                /* Section type */
+  Elf32_Word   sh_flags;               /* Section flags */
+  Elf32_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf32_Off    sh_offset;              /* Section file offset */
+  Elf32_Word   sh_size;                /* Section size in bytes */
+  Elf32_Word   sh_link;                /* Link to another section */
+  Elf32_Word   sh_info;                /* Additional section information */
+  Elf32_Word   sh_addralign;           /* Section alignment */
+  Elf32_Word   sh_entsize;             /* Entry size if section holds table */
+} Elf32_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF      0               /* Undefined section */
+#define SHN_LORESERVE  0xff00          /* Start of reserved indices */
+#define SHN_LOPROC     0xff00          /* Start of processor-specific */
+#define SHN_HIPROC     0xff1f          /* End of processor-specific */
+#define SHN_ABS                0xfff1          /* Associated symbol is absolute */
+#define SHN_COMMON     0xfff2          /* Associated symbol is common */
+#define SHN_HIRESERVE  0xffff          /* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL       0               /* Section header table entry unused */
+#define SHT_PROGBITS   1               /* Program data */
+#define SHT_SYMTAB     2               /* Symbol table */
+#define SHT_STRTAB     3               /* String table */
+#define SHT_RELA       4               /* Relocation entries with addends */
+#define SHT_HASH       5               /* Symbol hash table */
+#define SHT_DYNAMIC    6               /* Dynamic linking information */
+#define SHT_NOTE       7               /* Notes */
+#define SHT_NOBITS     8               /* Program space with no data (bss) */
+#define SHT_REL                9               /* Relocation entries, no addends */
+#define SHT_SHLIB      10              /* Reserved */
+#define SHT_DYNSYM     11              /* Dynamic linker symbol table */
+#define        SHT_NUM         12              /* Number of defined types.  */
+#define SHT_LOPROC     0x70000000      /* Start of processor-specific */
+#define SHT_HIPROC     0x7fffffff      /* End of processor-specific */
+#define SHT_LOUSER     0x80000000      /* Start of application-specific */
+#define SHT_HIUSER     0x8fffffff      /* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE      (1 << 0)        /* Writable */
+#define SHF_ALLOC      (1 << 1)        /* Occupies memory during execution */
+#define SHF_EXECINSTR  (1 << 2)        /* Executable */
+#define SHF_MASKPROC   0xf0000000      /* Processor-specific */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word   st_name;                /* Symbol name (string tbl index) */
+  Elf32_Addr   st_value;               /* Symbol value */
+  Elf32_Word   st_size;                /* Symbol size */
+  unsigned char        st_info;                /* Symbol type and binding */
+  unsigned char        st_other;               /* No defined meaning, 0 */
+  Elf32_Half   st_shndx;               /* Section index */
+} Elf32_Sym;
+
+/* Special section index.  */
+
+#define SHN_UNDEF      0               /* No section, undefined symbol.  */
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)             (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)             ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL      0               /* Local symbol */
+#define STB_GLOBAL     1               /* Global symbol */
+#define STB_WEAK       2               /* Weak symbol */
+#define        STB_NUM         3               /* Number of defined types.  */
+#define STB_LOPROC     13              /* Start of processor-specific */
+#define STB_HIPROC     15              /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE     0               /* Symbol type is unspecified */
+#define STT_OBJECT     1               /* Symbol is a data object */
+#define STT_FUNC       2               /* Symbol is a code object */
+#define STT_SECTION    3               /* Symbol associated with a section */
+#define STT_FILE       4               /* Symbol's name is file name */
+#define        STT_NUM         5               /* Number of defined types.  */
+#define STT_LOPROC     13              /* Start of processor-specific */
+#define STT_HIPROC     15              /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF      0               /* End of a chain.  */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr   r_offset;               /* Address */
+  Elf32_Word   r_info;                 /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr   r_offset;               /* Address */
+  Elf32_Word   r_info;                 /* Relocation type and symbol index */
+  Elf32_Sword  r_addend;               /* Addend */
+} Elf32_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)               ((val) >> 8)
+#define ELF32_R_TYPE(val)              ((val) & 0xff)
+#define ELF32_R_INFO(sym, type)                (((sym) << 8) + ((type) & 0xff))
+
+/* Program segment header.  */
+
+typedef struct {
+  Elf32_Word   p_type;                 /* Segment type */
+  Elf32_Off    p_offset;               /* Segment file offset */
+  Elf32_Addr   p_vaddr;                /* Segment virtual address */
+  Elf32_Addr   p_paddr;                /* Segment physical address */
+  Elf32_Word   p_filesz;               /* Segment size in file */
+  Elf32_Word   p_memsz;                /* Segment size in memory */
+  Elf32_Word   p_flags;                /* Segment flags */
+  Elf32_Word   p_align;                /* Segment alignment */
+} Elf32_Phdr;
+
+/* Legal values for p_type (segment type).  */
+
+#define        PT_NULL         0               /* Program header table entry unused */
+#define PT_LOAD                1               /* Loadable program segment */
+#define PT_DYNAMIC     2               /* Dynamic linking information */
+#define PT_INTERP      3               /* Program interpreter */
+#define PT_NOTE                4               /* Auxiliary information */
+#define PT_SHLIB       5               /* Reserved */
+#define PT_PHDR                6               /* Entry for header table itself */
+#define        PT_NUM          7               /* Number of defined types.  */
+#define PT_LOPROC      0x70000000      /* Start of processor-specific */
+#define PT_HIPROC      0x7fffffff      /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X           (1 << 0)        /* Segment is executable */
+#define PF_W           (1 << 1)        /* Segment is writable */
+#define PF_R           (1 << 2)        /* Segment is readable */
+#define PF_MASKPROC    0xf0000000      /* Processor-specific */
+
+#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
+                    (((X) & PF_W) ? PROT_WRITE : 0) | \
+                    (((X) & PF_X) ? PROT_EXEC : 0))
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword  d_tag;                  /* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;                        /* Integer value */
+      Elf32_Addr d_ptr;                        /* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL                0               /* Marks end of dynamic section */
+#define DT_NEEDED      1               /* Name of needed library */
+#define DT_PLTRELSZ    2               /* Size in bytes of PLT relocs */
+#define DT_PLTGOT      3               /* Processor defined value */
+#define DT_HASH                4               /* Address of symbol hash table */
+#define DT_STRTAB      5               /* Address of string table */
+#define DT_SYMTAB      6               /* Address of symbol table */
+#define DT_RELA                7               /* Address of Rela relocs */
+#define DT_RELASZ      8               /* Total size of Rela relocs */
+#define DT_RELAENT     9               /* Size of one Rela reloc */
+#define DT_STRSZ       10              /* Size of string table */
+#define DT_SYMENT      11              /* Size of one symbol table entry */
+#define DT_INIT                12              /* Address of init function */
+#define DT_FINI                13              /* Address of termination function */
+#define DT_SONAME      14              /* Name of shared object */
+#define DT_RPATH       15              /* Library search path */
+#define DT_SYMBOLIC    16              /* Start symbol search here */
+#define DT_REL         17              /* Address of Rel relocs */
+#define DT_RELSZ       18              /* Total size of Rel relocs */
+#define DT_RELENT      19              /* Size of one Rel reloc */
+#define DT_PLTREL      20              /* Type of reloc in PLT */
+#define DT_DEBUG       21              /* For debugging; unspecified */
+#define DT_TEXTREL     22              /* Reloc might modify .text */
+#define DT_JMPREL      23              /* Address of PLT relocs */
+#define        DT_NUM          24              /* Number used.  */
+#define DT_LOPROC      0x70000000      /* Start of processor-specific */
+#define DT_HIPROC      0x7fffffff      /* End of processor-specific */
+
+/* Standard 64 bit ELF types.  */
+
+typedef unsigned int Elf64_Addr    __attribute__ ((mode (DI)));
+typedef unsigned int Elf64_Half    __attribute__ ((mode (HI)));
+typedef unsigned int Elf64_Off     __attribute__ ((mode (DI)));
+typedef                 int Elf64_Sword   __attribute__ ((mode (SI)));
+typedef                 int Elf64_Sxword  __attribute__ ((mode (DI)));
+typedef unsigned int Elf64_Word    __attribute__ ((mode (SI)));
+typedef unsigned int Elf64_Xword   __attribute__ ((mode (DI)));
+typedef unsigned int Elf64_Byte    __attribute__ ((mode (QI)));
+typedef unsigned int Elf64_Section __attribute__ ((mode (HI)));
+
+/* 64 bit ELF file header.  */
+
+typedef struct
+{
+  unsigned char        e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf64_Half   e_type;                 /* Object file type */
+  Elf64_Half   e_machine;              /* Architecture */
+  Elf64_Word   e_version;              /* Object file version */
+  Elf64_Addr   e_entry;                /* Entry point virtual address */
+  Elf64_Off    e_phoff;                /* Program header table file offset */
+  Elf64_Off    e_shoff;                /* Section header table file offset */
+  Elf64_Word   e_flags;                /* Processor-specific flags */
+  Elf64_Half   e_ehsize;               /* ELF header size in bytes */
+  Elf64_Half   e_phentsize;            /* Program header table entry size */
+  Elf64_Half   e_phnum;                /* Program header table entry count */
+  Elf64_Half   e_shentsize;            /* Section header table entry size */
+  Elf64_Half   e_shnum;                /* Section header table entry count */
+  Elf64_Half   e_shstrndx;             /* Section header string table index */
+} Elf64_Ehdr;
+
+/* 64 bit section header.  */
+
+typedef struct
+{
+  Elf64_Word   sh_name;                /* Section name (string tbl index) */
+  Elf64_Word   sh_type;                /* Section type */
+  Elf64_Xword  sh_flags;               /* Section flags */
+  Elf64_Addr   sh_addr;                /* Section virtual addr at execution */
+  Elf64_Off    sh_offset;              /* Section file offset */
+  Elf64_Xword  sh_size;                /* Section size in bytes */
+  Elf64_Word   sh_link;                /* Link to another section */
+  Elf64_Word   sh_info;                /* Additional section information */
+  Elf64_Xword  sh_addralign;           /* Section alignment */
+  Elf64_Xword  sh_entsize;             /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* 64 bit symbol table entry.  */
+
+typedef struct
+{
+  Elf64_Word   st_name;                /* Symbol name (string tbl index) */
+  Elf64_Byte   st_info;                /* Symbol type and binding */
+  Elf64_Byte   st_other;               /* No defined meaning, 0 */
+  Elf64_Section        st_shndx;               /* Section index */
+  Elf64_Addr   st_value;               /* Symbol value */
+  Elf64_Xword  st_size;                /* Symbol size */
+} Elf64_Sym;
+
+/* The 64 bit st_info field is the same as the 32 bit one.  */
+
+#define ELF64_ST_BIND(val)             (((unsigned char) (val)) >> 4)
+#define ELF64_ST_TYPE(val)             ((val) & 0xf)
+#define ELF64_ST_INFO(bind, type)      (((bind) << 4) + ((type) & 0xf))
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  int a_type;                          /* Entry type */
+  union
+    {
+      long a_val;                      /* Integer value */
+      void *a_ptr;                     /* Pointer value */
+      void (*a_fcn) ();                        /* Function pointer value */
+    } a_un;
+} Elf32_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL                0               /* End of vector */
+#define AT_IGNORE      1               /* Entry should be ignored */
+#define AT_EXECFD      2               /* File descriptor of program */
+#define AT_PHDR                3               /* Program headers for program */
+#define AT_PHENT       4               /* Size of program header entry */
+#define AT_PHNUM       5               /* Number of program headers */
+#define AT_PAGESZ      6               /* System page size */
+#define AT_BASE                7               /* Base address of interpreter */
+#define AT_FLAGS       8               /* Flags */
+#define AT_ENTRY       9               /* Entry point of program */
+#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 */
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE     0               /* No reloc */
+#define R_386_32       1               /* Direct 32 bit  */
+#define R_386_PC32     2               /* PC relative 32 bit */
+#define R_386_GOT32    3               /* 32 bit GOT entry */
+#define R_386_PLT32    4               /* 32 bit PLT address */
+#define R_386_COPY     5               /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6               /* Create GOT entry */
+#define R_386_JMP_SLOT 7               /* Create PLT entry */
+#define R_386_RELATIVE 8               /* Adjust by program base */
+#define R_386_GOTOFF   9               /* 32 bit offset to GOT */
+#define R_386_GOTPC    10              /* 32 bit PC relative offset to GOT */
+
+/* SUN SPARC specific definitions.  */
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE   0               /* No reloc */
+#define R_SPARC_8      1               /* Direct 8 bit */
+#define R_SPARC_16     2               /* Direct 16 bit */
+#define R_SPARC_32     3               /* Direct 32 bit */
+#define R_SPARC_DISP8  4               /* PC relative 8 bit */
+#define R_SPARC_DISP16 5               /* PC relative 16 bit */
+#define R_SPARC_DISP32 6               /* PC relative 32 bit */
+#define R_SPARC_WDISP30        7               /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22        8               /* PC relative 22 bit shifted */
+#define R_SPARC_HI22   9               /* High 22 bit */
+#define R_SPARC_22     10              /* Direct 22 bit */
+#define R_SPARC_13     11              /* Direct 13 bit */
+#define R_SPARC_LO10   12              /* Truncated 10 bit */
+#define R_SPARC_GOT10  13              /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13  14              /* 13 bit GOT entry */
+#define R_SPARC_GOT22  15              /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10   16              /* PC relative 10 bit truncated */
+#define R_SPARC_PC22   17              /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18              /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY   19              /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20            /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21            /* Create PLT entry */
+#define R_SPARC_RELATIVE 22            /* Adjust by program base */
+#define R_SPARC_UA32   23              /* Direct 32 bit unaligned */
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER 1            /* A .noreorder directive was used */
+#define EF_MIPS_PIC      2             /* Contains PIC code */
+#define EF_MIPS_CPIC     4             /* Uses PIC calling sequence */
+#define EF_MIPS_ARCH     0xf0000000    /* MIPS architecture level */
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON 0xff00                /* Allocated common symbols */
+#define SHN_MIPS_SCOMMON 0xff03                /* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04     /* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST  0x70000000   /* Shared objects used in link */
+#define SHT_MIPS_CONFLICT 0x70000002   /* Conflicting symbols */
+#define SHT_MIPS_GPTAB   0x70000003    /* Global data area sizes */
+#define SHT_MIPS_UCODE   0x70000004    /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG   0x70000005    /* MIPS ECOFF debugging information */
+#define SHT_MIPS_REGINFO  0x70000006   /* Register usage information */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL 0x10000000      /* Must be part of global data area */
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;   /* -G value used for compilation */
+      Elf32_Word gt_unused;            /* Not used */
+    } gt_header;                       /* First entry in section */
+  struct
+    {
+      Elf32_Word gt_g_value;           /* If this value were used for -G */
+      Elf32_Word gt_bytes;             /* This many bytes would be used */
+    } gt_entry;                                /* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word   ri_gprmask;             /* General registers used */
+  Elf32_Word   ri_cprmask[4];          /* Coprocessor registers used */
+  Elf32_Sword  ri_gp_value;            /* $gp register value */
+} Elf32_RegInfo;
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE    0               /* No reloc */
+#define R_MIPS_16      1               /* Direct 16 bit */
+#define R_MIPS_32      2               /* Direct 32 bit */
+#define R_MIPS_REL32   3               /* PC relative 32 bit */
+#define R_MIPS_26      4               /* Direct 26 bit shifted */
+#define R_MIPS_HI16    5               /* High 16 bit */
+#define R_MIPS_LO16    6               /* Low 16 bit */
+#define R_MIPS_GPREL16 7               /* GP relative 16 bit */
+#define R_MIPS_LITERAL 8               /* 16 bit literal entry */
+#define R_MIPS_GOT16   9               /* 16 bit GOT entry */
+#define R_MIPS_PC16    10              /* PC relative 16 bit */
+#define R_MIPS_CALL16  11              /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32 12              /* GP relative 32 bit */
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO        0x70000000      /* Register usage information */
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001        /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002        /* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003        /* Checksum */
+#define DT_MIPS_IVERSION     0x70000004        /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS       0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006        /* Base address */
+#define DT_MIPS_CONFLICT     0x70000008        /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST             0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a        /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b        /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010        /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011        /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012        /* First external DYNSYM */
+#define DT_MIPS_GOTSYM      0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014        /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP      0x70000016        /* Address of debug map pointer */
+
+/* Legal values for DT_MIPS_FLAG Elf32_Dyn entry.  */
+
+#define RHF_NONE                  0            /* No flags */
+#define RHF_QUICKSTART            (1 << 0)     /* Use quickstart */
+#define RHF_NOTPOT                (1 << 1)     /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)    /* Ignore LD_LIBRARY_PATH */
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word   l_name;                 /* Name (string table index) */
+  Elf32_Word   l_time_stamp;           /* Timestamp */
+  Elf32_Word   l_checksum;             /* Checksum */
+  Elf32_Word   l_version;              /* Interface version */
+  Elf32_Word   l_flags;                /* Flags */
+} Elf32_Lib;
+
+/* Legal values for l_flags.  */
+
+#define LL_EXACT_MATCH   (1 << 0)      /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)     /* Ignore interface version */
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+
+#endif /* elf.h */
diff --git a/gnu/libexec/ld.so/ld.so/mips/elf_abi.h b/gnu/libexec/ld.so/ld.so/mips/elf_abi.h
new file mode 100644 (file)
index 0000000..89a992a
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 1995 Erik Theisen
+ * 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. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifndef _ELF_ABI_H_
+#define _ELF_ABI_H_
+
+#include <machine/types.h>
+
+/*
+ * These typedefs needs to be handled better -
+ *  doesn't work on 64-bit machines.  Note:
+ *  there currently isn't a 64-bit ABI.
+ */
+typedef u_int32_t       Elf32_Addr;     /* Unsigned program address */
+typedef u_int32_t       Elf32_Off;      /* Unsigned file offset */
+typedef int32_t         Elf32_Sword;    /* Signed large integer */
+typedef u_int32_t       Elf32_Word;     /* Unsigned large integer */
+typedef u_int16_t       Elf32_Half;     /* Unsigned medium integer */
+
+/* e_ident[] identification indexes */
+#define EI_MAG0         0               /* file ID */
+#define EI_MAG1         1               /* file ID */
+#define EI_MAG2         2               /* file ID */
+#define EI_MAG3         3               /* file ID */
+#define EI_CLASS        4               /* file class */
+#define EI_DATA         5               /* data encoding */
+#define EI_VERSION      6               /* ELF header version */
+#define EI_PAD          7               /* start of pad bytes */
+#define EI_NIDENT       16              /* Size of e_ident[] */
+
+/* e_ident[] magic number */
+#define ELFMAG0         0x7f            /* e_ident[EI_MAG0] */
+#define ELFMAG1         'E'             /* e_ident[EI_MAG1] */
+#define ELFMAG2         'L'             /* e_ident[EI_MAG2] */
+#define ELFMAG3         'F'             /* e_ident[EI_MAG3] */
+#define ELFMAG          "\177ELF"       /* magic */
+#define SELFMAG         4               /* size of magic */
+
+/* e_ident[] file class */
+#define ELFCLASSNONE    0               /* invalid */
+#define ELFCLASS32      1               /* 32-bit objs */
+#define ELFCLASS64      2               /* 64-bit objs */
+#define ELFCLASSNUM     3               /* number of classes */
+
+/* e_ident[] data encoding */
+#define ELFDATANONE     0               /* invalid */
+#define ELFDATA2LSB     1               /* Little-Endian */
+#define ELFDATA2MSB     2               /* Big-Endian */
+#define ELFDATANUM      3               /* number of data encode defines */
+
+/* e_ident */
+#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                      (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                      (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                      (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* ELF Header */
+typedef struct elfhdr{
+        unsigned char   e_ident[EI_NIDENT]; /* ELF Identification */
+        Elf32_Half      e_type;         /* object file type */
+        Elf32_Half      e_machine;      /* machine */
+        Elf32_Word      e_version;      /* object file version */
+        Elf32_Addr      e_entry;        /* virtual entry point */
+        Elf32_Off       e_phoff;        /* program header table offset */
+        Elf32_Off       e_shoff;        /* section header table offset */
+        Elf32_Word      e_flags;        /* processor-specific flags */
+        Elf32_Half      e_ehsize;       /* ELF header size */
+        Elf32_Half      e_phentsize;    /* program header entry size */
+        Elf32_Half      e_phnum;        /* number of program header entries */
+        Elf32_Half      e_shentsize;    /* section header entry size */
+        Elf32_Half      e_shnum;        /* number of section header entries */
+        Elf32_Half      e_shstrndx;     /* section header table's "section 
+                                           header string table" entry offset */
+} Elf32_Ehdr;
+
+/* e_type */
+#define ET_NONE         0               /* No file type */
+#define ET_REL          1               /* relocatable file */
+#define ET_EXEC         2               /* executable file */
+#define ET_DYN          3               /* shared object file */
+#define ET_CORE         4               /* core file */
+#define ET_NUM          5               /* number of types */
+#define ET_LOPROC       0xff00          /* reserved range for processor */
+#define ET_HIPROC       0xffff          /*  specific e_type */
+
+/* e_machine */
+#define EM_NONE         0               /* No Machine */
+#define EM_M32          1               /* AT&T WE 32100 */
+#define EM_SPARC        2               /* SPARC */
+#define EM_386          3               /* Intel 80386 */
+#define EM_68K          4               /* Motorola 68000 */
+#define EM_88K          5               /* Motorola 88000 */
+#define EM_486          6               /* Intel 80486 - unused? */
+#define EM_860          7               /* Intel 80860 */
+#define EM_MIPS         8               /* MIPS R3000 Big-Endian only */
+/* 
+ * Don't know if EM_MIPS_RS4_BE,
+ * EM_SPARC64, EM_PARISC,
+ * or EM_PPC are ABI compliant
+ */
+#define EM_MIPS_RS4_BE  10              /* MIPS R4000 Big-Endian */
+#define EM_SPARC64      11              /* SPARC v9 64-bit unoffical */
+#define EM_PARISC       15              /* HPPA */
+#define EM_PPC          20              /* PowerPC */
+#define EM_NUM          13              /* number of machine types */
+
+/* Version */
+#define EV_NONE         0               /* Invalid */
+#define EV_CURRENT      1               /* Current */
+#define EV_NUM          2               /* number of versions */
+
+/* Section Header */
+typedef struct {
+        Elf32_Word      sh_name;        /* name - index into section header
+                                           string table section */
+        Elf32_Word      sh_type;        /* type */
+        Elf32_Word      sh_flags;       /* flags */
+        Elf32_Addr      sh_addr;        /* address */
+        Elf32_Off       sh_offset;      /* file offset */
+        Elf32_Word      sh_size;        /* section size */
+        Elf32_Word      sh_link;        /* section header table index link */
+        Elf32_Word      sh_info;        /* extra information */
+        Elf32_Word      sh_addralign;   /* address alignment */
+        Elf32_Word      sh_entsize;     /* section entry size */
+} Elf32_Shdr;
+
+/* Special Section Indexes */
+#define SHN_UNDEF       0               /* undefined */
+#define SHN_LORESERVE   0xff00          /* lower bounds of reserved indexes */
+#define SHN_LOPROC      0xff00          /* reserved range for processor */
+#define SHN_HIPROC      0xff1f          /*   specific section indexes */
+#define SHN_ABS         0xfff1          /* absolute value */
+#define SHN_COMMON      0xfff2          /* common symbol */
+#define SHN_HIRESERVE   0xffff          /* upper bounds of reserved indexes */
+
+/* sh_type */
+#define SHT_NULL        0               /* inactive */
+#define SHT_PROGBITS    1               /* program defined information */
+#define SHT_SYMTAB      2               /* symbol table section */
+#define SHT_STRTAB      3               /* string table section */
+#define SHT_RELA        4               /* relocation section with addends*/
+#define SHT_HASH        5               /* symbol hash table section */
+#define SHT_DYNAMIC     6               /* dynamic section */
+#define SHT_NOTE        7               /* note section */
+#define SHT_NOBITS      8               /* no space section */
+#define SHT_REL         9               /* relation section without addends */
+#define SHT_SHLIB       10              /* reserved - purpose unknown */
+#define SHT_DYNSYM      11              /* dynamic symbol table section */
+#define SHT_NUM         12              /* number of section types */
+#define SHT_LOPROC      0x70000000      /* reserved range for processor */
+#define SHT_HIPROC      0x7fffffff      /*  specific section header types */
+#define SHT_LOUSER      0x80000000      /* reserved range for application */
+#define SHT_HIUSER      0xffffffff      /*  specific indexes */
+
+/* Section names */
+#define ELF_BSS         ".bss"          /* uninitialized data */
+#define ELF_DATA        ".data"         /* initialized data */
+#define ELF_DEBUG       ".debug"        /* debug */
+#define ELF_DYNAMIC     ".dynamic"      /* dynamic linking information */
+#define ELF_DYNSTR      ".dynstr"       /* dynamic string table */
+#define ELF_DYNSYM      ".dynsym"       /* dynamic symbol table */
+#define ELF_FINI        ".fini"         /* termination code */
+#define ELF_GOT         ".got"          /* global offset table */
+#define ELF_HASH        ".hash"         /* symbol hash table */
+#define ELF_INIT        ".init"         /* initialization code */
+#define ELF_REL_DATA    ".rel.data"     /* relocation data */
+#define ELF_REL_FINI    ".rel.fini"     /* relocation termination code */
+#define ELF_REL_INIT    ".rel.init"     /* relocation initialization code */
+#define ELF_REL_DYN     ".rel.dyn"      /* relocaltion dynamic link info */
+#define ELF_REL_RODATA  ".rel.rodata"   /* relocation read-only data */
+#define ELF_REL_TEXT    ".rel.text"     /* relocation code */
+#define ELF_RODATA      ".rodata"       /* read-only data */
+#define ELF_SHSTRTAB    ".shstrtab"     /* section header string table */
+#define ELF_STRTAB      ".strtab"       /* string table */
+#define ELF_SYMTAB      ".symtab"       /* symbol table */
+#define ELF_TEXT        ".text"         /* code */
+
+/* Section Attribute Flags - sh_flags */
+#define SHF_WRITE       0x1             /* Writable */
+#define SHF_ALLOC       0x2             /* occupies memory */
+#define SHF_EXECINSTR   0x4             /* executable */
+#define SHF_MASKPROC    0xf0000000      /* reserved bits for processor */
+                                        /*  specific section attributes */
+
+/* Symbol Table Entry */
+typedef struct elf32_sym {
+        Elf32_Word      st_name;        /* name - index into string table */
+        Elf32_Addr      st_value;       /* symbol value */
+        Elf32_Word      st_size;        /* symbol size */
+        unsigned char   st_info;        /* type and binding */
+        unsigned char   st_other;       /* 0 - no defined meaning */
+        Elf32_Half      st_shndx;       /* section header index */
+} Elf32_Sym;
+
+/* Symbol table index */
+#define STN_UNDEF       0               /* undefined */
+
+/* Extract symbol info - st_info */
+#define ELF32_ST_BIND(x)        ((x) >> 4)
+#define ELF32_ST_TYPE(x)        (((unsigned int) x) & 0xf)
+#define ELF32_ST_INFO(b,t)      (((b) << 4) + ((t) & 0xf))
+
+/* Symbol Binding - ELF32_ST_BIND - st_info */
+#define STB_LOCAL       0               /* Local symbol */
+#define STB_GLOBAL      1               /* Global symbol */
+#define STB_WEAK        2               /* like global - lower precedence */
+#define STB_NUM         3               /* number of symbol bindings */
+#define STB_LOPROC      13              /* reserved range for processor */
+#define STB_HIPROC      15              /*  specific symbol bindings */
+
+/* Symbol type - ELF32_ST_TYPE - st_info */
+#define STT_NOTYPE      0               /* not specified */
+#define STT_OBJECT      1               /* data object */
+#define STT_FUNC        2               /* function */
+#define STT_SECTION     3               /* section */
+#define STT_FILE        4               /* file */
+#define STT_NUM         5               /* number of symbol types */
+#define STT_LOPROC      13              /* reserved range for processor */
+#define STT_HIPROC      15              /*  specific symbol types */
+
+/* Relocation entry with implicit addend */
+typedef struct 
+{
+        Elf32_Addr      r_offset;       /* offset of relocation */
+        Elf32_Word      r_info;         /* symbol table index and type */
+} Elf32_Rel;
+
+/* Relocation entry with explicit addend */
+typedef struct 
+{
+        Elf32_Addr      r_offset;       /* offset of relocation */
+        Elf32_Word      r_info;         /* symbol table index and type */
+        Elf32_Sword     r_addend;
+} Elf32_Rela;
+
+/* Extract relocation info - r_info */
+#define ELF32_R_SYM(i)          ((i) >> 8)
+#define ELF32_R_TYPE(i)         ((unsigned char) (i))
+#define ELF32_R_INFO(s,t)       (((s) << 8) + (unsigned char)(t))
+
+/* Program Header */
+typedef struct {
+        Elf32_Word      p_type;         /* segment type */
+        Elf32_Off       p_offset;       /* segment offset */
+        Elf32_Addr      p_vaddr;        /* virtual address of segment */
+        Elf32_Addr      p_paddr;        /* physical address - ignored? */
+        Elf32_Word      p_filesz;       /* number of bytes in file for seg. */
+        Elf32_Word      p_memsz;        /* number of bytes in mem. for seg. */
+        Elf32_Word      p_flags;        /* flags */
+        Elf32_Word      p_align;        /* memory alignment */
+} Elf32_Phdr;
+
+/* Segment types - p_type */
+#define PT_NULL         0               /* unused */
+#define PT_LOAD         1               /* loadable segment */
+#define PT_DYNAMIC      2               /* dynamic linking section */
+#define PT_INTERP       3               /* the RTLD */
+#define PT_NOTE         4               /* auxiliary information */
+#define PT_SHLIB        5               /* reserved - purpose undefined */
+#define PT_PHDR         6               /* program header */
+#define PT_NUM          7               /* Number of segment types */
+#define PT_LOPROC       0x70000000      /* reserved range for processor */
+#define PT_HIPROC       0x7fffffff      /*  specific segment types */
+
+/* Segment flags - p_flags */
+#define PF_X            0x1             /* Executable */
+#define PF_W            0x2             /* Writable */
+#define PF_R            0x4             /* Readable */
+#define PF_MASKPROC     0xf0000000      /* reserved bits for processor */
+                                        /*  specific segment flags */
+
+
+#if 0
+#error No ELF RTLD support yet
+/* Dynamic structure */
+typedef struct 
+{
+        Elf32_Sword     d_tag;          /* controls meaning of d_val */
+        union 
+        {
+                Elf32_Word      d_val;  /* Multiple meanings - see d_tag */
+                Elf32_Addr      d_ptr;  /* program virtual address */
+        } d_un;
+} Elf32_Dyn;
+
+extern Elf32_Dyn        _DYNAMIC[];
+
+/* Dynamic Array Tags - d_tag */
+#define DT_NULL         0               /* marks end of _DYNAMIC array */
+#define DT_NEEDED       1               /* string table offset of needed lib */
+#define DT_PLTRELSZ     2               /* size of relocation entries in PLT */
+#define DT_PLTGOT       3               /* address PLT/GOT */
+#define DT_HASH         4               /* address of symbol hash table */
+#define DT_STRTAB       5               /* address of string table */
+#define DT_SYMTAB       6               /* address of symbol table */
+#define DT_RELA         7               /* address of relocation table */
+#define DT_RELASZ       8               /* size of relocation table */
+#define DT_RELAENT      9               /* size of relocation entry */
+#define DT_STRSZ        10              /* size of string table */
+#define DT_SYMENT       11              /* size of symbol table entry */
+#define DT_INIT         12              /* address of initialization func. */
+#define DT_FINI         13              /* address of termination function */
+#define DT_SONAME       14              /* string table offset of shared obj */
+#define DT_RPATH        15              /* string table offset of library
+                                        /*  search path */
+#define DT_SYMBOLIC     16              /* start sym search in shared obj. */
+#define DT_REL          17              /* address of rel. tbl. w addends */
+#define DT_RELSZ        18              /* size of DT_REL relocation table */
+#define DT_RELENT       19              /* size of DT_REL relocation entry */
+#define DT_PLTREL       20              /* PLT referenced relocation entry */
+#define DT_DEBUG        21              /* bugger */
+#define DT_TEXTREL      22              /* Allow rel. mod. to unwritable seg */
+#define DT_JMPREL       23              /* add. of PLT's relocation entries */
+#define DT_LOPROC       0x70000000      /* reserved range for processor */
+#define DT_HIPROC       0x7fffffff      /*  specific dynamic array tags */
+#endif
+
+        
+#endif /* _ELF_ABI_H_ */
+
diff --git a/gnu/libexec/ld.so/ld.so/mips/elfinterp.c b/gnu/libexec/ld.so/ld.so/mips/elfinterp.c
new file mode 100644 (file)
index 0000000..de1507e
--- /dev/null
@@ -0,0 +1,449 @@
+/* Run an ELF binary on a OpenBSD 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
+
+/* Program to load an ELF binary on a OpenBSD 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <elf.h>
+
+#include "hash.h"
+#include "syscall.h"
+#include "sysdep.h"
+#include "string.h"
+
+extern char *_dl_progname;
+
+/* Search loaded objects' symbol tables for a definition of
+   the symbol UNDEF_NAME.  If NOSELF is nonzero, then *REF
+   cannot satisfy the reference itself; some different binding
+   must be found.  */
+
+Elf32_Addr
+_dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
+                  struct elf_resolve *symbol_scope,
+                  const char *reference_name,
+                  int noself)
+{
+  unsigned long int hash = _dl_elf_hash (undef_name);
+  struct elf_resolve *map;
+  struct
+    {
+      Elf32_Addr a;
+      const Elf32_Sym *s;
+    } weak_value = { 0, NULL };
+
+  /* Search the relevant loaded objects for a definition.  */
+  for (map = symbol_scope; map; map = map->next)
+    {
+      const Elf32_Sym *symtab;
+      const char *strtab;
+      Elf32_Word symidx;
+
+      symtab = ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]);
+      strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]);
+
+      /* Search the appropriate hash bucket in this object's symbol table
+        for a definition for the same symbol name.  */
+      for (symidx = map->elf_buckets[hash % map->nbucket];
+          symidx != STN_UNDEF;
+          symidx = map->chains[symidx])
+       {
+         const Elf32_Sym *sym = &symtab[symidx];
+
+         if (sym->st_value == 0 || /* No value.  */
+             sym->st_shndx == SHN_UNDEF || /* PLT entry.  */
+             (noself && sym == *ref))  /* The reference can't define it.  */
+           continue;
+
+         switch (ELF32_ST_TYPE (sym->st_info))
+           {
+           case STT_NOTYPE:
+           case STT_FUNC:
+           case STT_OBJECT:
+             break;
+           default:
+             /* Not a code/data definition.  */
+             continue;
+           }
+
+         if (sym != *ref && _dl_strcmp (strtab + sym->st_name, undef_name))
+           /* Not the symbol we are looking for.  */
+           continue;
+
+         switch (ELF32_ST_BIND (sym->st_info))
+           {
+           case STB_GLOBAL:
+             /* Global definition.  Just what we need.  */
+             *ref = sym;
+             return (Elf32_Word)map->loadoffs;
+           case STB_WEAK:
+             /* Weak definition.  Use this value if we don't find another.  */
+             if (! weak_value.s)
+               {
+                 weak_value.s = sym;
+                 weak_value.a = (Elf32_Word)map->loadoffs;
+               }
+             break;
+           default:
+             /* Local symbols are ignored.  */
+             break;
+           }
+       }
+    }
+
+  if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK) {
+      _dl_fdprintf(2,"%s: undefined symbol: '%s' %x\n", _dl_progname, undef_name,(*ref)->st_info);
+  }
+
+  *ref = weak_value.s;
+  return weak_value.a;
+}
+
+
+/* Get link_map for this object.  */
+static struct elf_resolve *
+elf_machine_runtime_link_map (Elf32_Addr gpreg)
+{
+  struct elf_resolve *l = 0;
+  Elf32_Addr *got = (Elf32_Addr *) (gpreg - 0x7ff0);
+  Elf32_Word g1;
+
+  g1 = ((Elf32_Word *) got)[1];
+
+  if (g1 & 0x80000000)
+    l = (void *) (g1 & ~0x80000000);
+#if 0
+  else
+    l = LOOK_UP_A_TABLE (got);
+#endif
+  return l;
+}
+
+/* This function is called from assembler function _dl_runtime_resolve
+   which converts special argument registers t7 ($15) and t8 ($24):
+     t7  address to return to the caller of the function
+     t8  index for this function symbol in .dynsym
+   to usual c arguments.  */
+
+Elf32_Addr
+__dl_runtime_resolve (Elf32_Word sym_index,
+                     Elf32_Word return_address,
+                     Elf32_Addr old_gpreg,
+                     Elf32_Addr stub_return_address)
+{
+  struct elf_resolve *l = elf_machine_runtime_link_map (old_gpreg);
+
+  const Elf32_Sym *const symtab
+    = (const Elf32_Sym *) (l->loadoffs + l->dynamic_info[DT_SYMTAB]);
+  char *strtab
+    = (void *) (l->loadoffs + l->dynamic_info[DT_STRTAB]);
+  Elf32_Addr *got
+    = (Elf32_Addr *) (l->loadoffs + l->dynamic_info[DT_PLTGOT]);
+
+  const Elf32_Word local_gotno
+    = (const Elf32_Word) l->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];
+  const Elf32_Word gotsym
+    = (const Elf32_Word) l->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
+  
+  const Elf32_Sym *definer;
+  Elf32_Addr loadbase;
+  Elf32_Addr funcaddr;
+  struct elf_resolve *scope, *real_next;
+
+  /* Look up the symbol's run-time value.  */
+
+  real_next = l->next;
+  if (l->dynamic_info[DT_SYMBOLIC])
+    {
+      l->next = _dl_loaded_modules;
+      if (l->prev)
+       l->prev->next = real_next;
+      scope = l;
+    }
+  else
+    scope = _dl_loaded_modules;
+
+  definer = &symtab[sym_index];
+  loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer,
+                                scope, l->libname, 0);
+
+  
+  /* Restore list frobnication done above for DT_SYMBOLIC.  */
+  l->next = real_next;
+  if (l->prev)
+    l->prev->next = l;
+
+  /* Apply the relocation with that value.  */
+  funcaddr = loadbase + definer->st_value;
+  *(got + local_gotno + sym_index - gotsym) = funcaddr;
+
+  return funcaddr;
+}
+
+asm ("\n\
+       .text\n\
+       .align  2\n\
+       .globl  _dl_runtime_resolve\n\
+       .type   _dl_runtime_resolve,@function\n\
+       .ent    _dl_runtime_resolve\n\
+_dl_runtime_resolve:\n\
+       .set noreorder\n\
+       # Save old GP to $3.\n\
+       move    $3,$28\n\
+       # Modify t9 ($25) so as to point .cpload instruction.\n\
+       addu    $25,8\n\
+       # Compute GP.\n\
+       .cpload $25\n\
+       .set reorder\n\
+       # Save arguments and sp value in stack.\n\
+       subu    $29, 40\n\
+       .cprestore 32\n\
+       sw      $15, 36($29)\n\
+       sw      $4, 12($29)\n\
+       sw      $5, 16($29)\n\
+       sw      $6, 20($29)\n\
+       sw      $7, 24($29)\n\
+       sw      $16, 28($29)\n\
+       move    $16, $29\n\
+       move    $4, $24\n\
+       move    $5, $15\n\
+       move    $6, $3\n\
+       move    $7, $31\n\
+       jal     __dl_runtime_resolve\n\
+       move    $29, $16\n\
+       lw      $31, 36($29)\n\
+       lw      $4, 12($29)\n\
+       lw      $5, 16($29)\n\
+       lw      $6, 20($29)\n\
+       lw      $7, 24($29)\n\
+       lw      $16, 28($29)\n\
+       addu    $29, 40\n\
+       move    $25, $2\n\
+       jr      $25\n\
+       .end    _dl_runtime_resolve\n\
+");
+
+
+int 
+_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr,
+                                 int rel_size, int lazy)
+{
+  int i;
+  char *strtab;
+  int reloc_type;
+  int goof = 0;
+  Elf32_Sym *symtab;
+  const Elf32_Sym *symbol;
+  const Elf32_Sym *ref;
+  Elf32_Rel *rpnt;
+  unsigned int *reloc_addr;
+  unsigned int symbol_addr;
+  int symtab_index;
+  struct elf_resolve *real_next, *scope;
+
+  /* Now parse the relocation information */
+
+  rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadoffs);
+  rel_size = rel_size / sizeof (Elf32_Rel);
+
+  symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadoffs);
+  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadoffs);
+
+  /* Set scope.  */
+  real_next = tpnt->next;
+  if (tpnt->dynamic_info[DT_SYMBOLIC]) {
+      if (tpnt->prev)
+          tpnt->prev->next = real_next;
+      tpnt->next = _dl_loaded_modules;
+          scope = tpnt;
+  }
+  else
+      scope = _dl_loaded_modules;
+
+  for (i = 0; i < rel_size; i++, rpnt++) {
+      reloc_addr = (int *) (tpnt->loadoffs + (int) rpnt->r_offset);
+      reloc_type = ELF32_R_TYPE (rpnt->r_info);
+      symtab_index = ELF32_R_SYM (rpnt->r_info);
+      symbol = symtab + symtab_index;
+      symbol_addr = (unsigned int) tpnt->loadoffs;
+      ref = symbol;
+
+      if (tpnt->libtype == program_interpreter
+         && (!symtab_index || _dl_symbol (strtab + symbol->st_name)))
+       continue;
+
+      if (symtab_index == 0xffffff)
+       continue;
+
+      if (symtab_index &&
+          !(ELF32_ST_BIND (ref->st_info) == STB_LOCAL &&
+            ELF32_ST_TYPE (ref->st_info) == STT_NOTYPE)) {
+
+          symbol_addr = (unsigned int)
+            _dl_lookup_symbol (strtab + symbol->st_name, &ref,
+                                scope, tpnt->libname, 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 (!ref && ELF32_ST_BIND (symbol->st_info) == STB_GLOBAL) {
+             _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+                           _dl_progname, strtab + symbol->st_name);
+             goof++;
+         }
+      }
+      switch (reloc_type)
+      {
+       case R_MIPS_NONE:
+         break;
+
+       case R_MIPS_REL32:
+         if (ELF32_ST_BIND (symbol->st_info) == STB_LOCAL
+               && (ELF32_ST_TYPE (symbol->st_info) == STT_SECTION      
+                || ELF32_ST_TYPE (symbol->st_info) == STT_NOTYPE)) {    
+              *reloc_addr += (unsigned int) tpnt->loadoffs;
+          }
+          else {
+              *reloc_addr += ref ? symbol_addr + ref->st_value : 0;
+          }
+         break;
+
+       default:
+         _dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname);
+         if (symtab_index)
+              _dl_fdprintf (2, "'%s'", strtab + symbol->st_name);
+         _dl_fdprintf (2, "\n");
+         _dl_exit (1);
+      }
+
+  }
+  /* Restore list frobnication done above for DT_SYMBOLIC.  */
+  tpnt->next = real_next;
+  if (tpnt->prev)
+    tpnt->prev->next = tpnt;
+
+  return goof;
+}
+
+/* Relocate GOT. */
+void
+elf_machine_got_rel (struct elf_resolve *map)
+{
+  Elf32_Addr *got;
+  Elf32_Sym *sym = 0;
+  int i, n;
+  struct elf_resolve *real_next, *scope;
+  char *strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]);
+
+  Elf32_Addr resolve (const Elf32_Sym *sym)
+  {
+      const Elf32_Sym *ref;
+      Elf32_Addr sym_addr;
+
+      sym_addr = _dl_lookup_symbol (strtab + sym->st_name, &ref, scope,
+                                        map->libname, 1);
+      if(ref)
+          return sym_addr + ref->st_value;
+      else
+          return 0;
+   }
+
+  got = (Elf32_Addr *) ((void *) map->loadoffs + map->dynamic_info[DT_PLTGOT]);
+
+  /* Add the run-time display to all local got entries. */
+  i = (got[1] & 0x80000000)? 2: 1;
+  n = map->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];
+  while (i < n) {
+    got[i++] += (Elf32_Addr)map->loadoffs;
+  }
+
+  /* Set scope.  */
+  real_next = map->next;
+  if (map->dynamic_info[DT_SYMBOLIC]) {
+      if (map->prev)
+       map->prev->next = real_next;
+      map->next = _dl_loaded_modules;
+      scope = map;
+  }
+  else
+    scope = _dl_loaded_modules;
+
+  /* Handle global got entries. */
+  got += n;
+  sym = (Elf32_Sym *) ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]);
+  sym += map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
+  i = (map->dynamic_info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM]
+       - map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]);
+
+  while (i--) {
+      if (sym->st_shndx == SHN_UNDEF) {
+         if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC) {
+#if 0 /*XXX*/
+             if (sym->st_value /* && maybe_stub (sym->st_value) */) {
+               *got = sym->st_value + (Elf32_Word)map->loadoffs;
+              }
+             else {
+               *got = resolve (sym);
+              }
+#else
+             *got = resolve (sym);
+#endif
+         }
+         else /* if (*got == 0 || *got == QS) */ {
+           *got = resolve (sym);
+          }
+      }
+      else if (sym->st_shndx == SHN_COMMON) {
+       *got = resolve (sym);
+      }
+      else if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC
+              /* && maybe_stub (*got) */) {
+       *got += (Elf32_Word)map->loadoffs;
+      }
+      else {
+       *got = sym->st_value + (Elf32_Word)map->loadoffs;
+      }
+
+      got++;
+      sym++;
+    }
+
+  /* Restore list frobnication done above for DT_SYMBOLIC.  */
+  map->next = real_next;
+  if (map->prev)
+    map->prev->next = map;
+
+  return;
+}
diff --git a/gnu/libexec/ld.so/ld.so/mips/link.h b/gnu/libexec/ld.so/ld.so/mips/link.h
new file mode 100644 (file)
index 0000000..2ce1048
--- /dev/null
@@ -0,0 +1,247 @@
+/* Run-time dynamic linker data structures for loaded ELF shared objects.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef        _LINK_H
+#define        _LINK_H 1
+
+#include <elf.h>
+#include <elf-machine.h>
+
+
+/* Rendezvous structure used by the run-time dynamic linker to communicate
+   details of shared object loading to the debugger.  If the executable's
+   dynamic section has a DT_MIPS_RLD_MAP element, the run-time linker sets
+   that element's value to the address where this structure can be found.  */
+
+struct r_debug
+  {
+    int r_version;             /* Version number for this protocol.  */
+
+    struct link_map *r_map;    /* Head of the chain of loaded objects.  */
+
+    /* This is the address of a function internal to the run-time linker,
+       that will always be called when the linker begins to map in a
+       library or unmap it, and again when the mapping change is complete.
+       The debugger can set a breakpoint at this address if it wants to
+       notice shared object mapping changes.  */
+    Elf32_Addr r_brk;
+    enum
+      {
+       /* This state value describes the mapping change taking place when
+          the `r_brk' address is called.  */
+       RT_CONSISTENT,          /* Mapping change is complete.  */
+       RT_ADD,                 /* Beginning to add a new object.  */
+       RT_DELETE,              /* Beginning to remove an object mapping.  */
+      } r_state;
+
+    Elf32_Addr r_ldbase;       /* Base address the linker is loaded at.  */
+  };
+
+/* This symbol refers to the "dynamic structure" in the `.dynamic' section
+   of whatever module refers to `_DYNAMIC'.  So, to find its own
+   `struct r_debug', a program could do:
+     for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL)
+       if (dyn->d_tag == DT_MIPS_RLD_MAP) r_debug = (struct r_debug) dyn->d_un.d_ptr;
+   */
+
+extern Elf32_Dyn _DYNAMIC[];
+
+
+/* Structure describing a loaded shared object.  The `l_next' and `l_prev'
+   members form a chain of all the shared objects loaded at startup.
+
+   These data structures exist in space used by the run-time dynamic linker;
+   modifying them may have disastrous results.  */
+
+struct link_map
+  {
+    /* These first few members are part of the protocol with the debugger.
+       This is the same format used in SVR4.  */
+
+    Elf32_Addr l_addr;         /* Base address shared object is loaded at.  */
+    char *l_name;              /* Absolute file name object was found in.  */
+    Elf32_Dyn *l_ld;           /* Dynamic section of the shared object.  */
+    struct link_map *l_next, *l_prev; /* Chain of loaded objects.  */
+
+    /* All following members are internal to the dynamic linker.
+       They may change without notice.  */
+
+    const char *l_libname;     /* Name requested (before search).  */
+
+    /* Indexed pointers to dynamic section.  */
+    Elf32_Dyn *l_info[DT_NUM + DT_PROCNUM];
+
+    const Elf32_Phdr *l_phdr;  /* Pointer to program header table in core.  */
+    Elf32_Word l_phnum;                /* Number of program header entries.  */
+    Elf32_Addr l_entry;                /* Entry point location.  */
+
+    /* Symbol hash table.  */
+    Elf32_Word l_nbuckets;
+    const Elf32_Word *l_buckets, *l_chain;
+
+    unsigned int l_opencount;  /* Reference count for dlopen/dlclose.  */
+    enum                       /* Where this object came from.  */
+      {
+       lt_executable,          /* The main executable program.  */
+       lt_interpreter,         /* The interpreter: the dynamic linker.  */
+       lt_library,             /* Library needed by main executable.  */
+       lt_loaded,              /* Extra run-time loaded shared object.  */
+      } l_type:2;
+    unsigned int l_deps_loaded:1; /* Nonzero if DT_NEEDED items loaded.  */
+    unsigned int l_relocated:1;        /* Nonzero if object's relocations done.  */
+    unsigned int l_init_called:1; /* Nonzero if DT_INIT function called.  */
+    unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs.  */
+  };
+\f
+/* Internal functions of the run-time dynamic linker.
+   These can be accessed if you link again the dynamic linker
+   as a shared library, as in `-lld' or `/lib/ld.so' explicitly;
+   but are not normally of interest to user programs.
+
+   The `-ldl' library functions in <dlfcn.h> provide a simple
+   user interface to run-time dynamic linking.  */
+
+
+/* File descriptor referring to the zero-fill device.  */
+extern int _dl_zerofd;
+
+/* OS-dependent function to open the zero-fill device.  */
+extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */
+
+/* OS-dependent function to write a message on the standard output.
+   All arguments are `const char *'; args until a null pointer
+   are concatenated to form the message to print.  */
+extern void _dl_sysdep_message (const char *string, ...);
+
+/* OS-dependent function to give a fatal error message and exit
+   when the dynamic linker fails before the program is fully linked.
+   All arguments are `const char *'; args until a null pointer
+   are concatenated to form the message to print.  */
+extern void _dl_sysdep_fatal (const char *string, ...)
+     __attribute__ ((__noreturn__));
+
+/* Nonzero if the program should be "secure" (i.e. it's setuid or somesuch).
+   This tells the dynamic linker to ignore environment variables.  */
+extern int _dl_secure;
+
+/* This function is called by all the internal dynamic linker functions
+   when they encounter an error.  ERRCODE is either an `errno' code or
+   zero; OBJECT is the name of the problematical shared object, or null if
+   it is a general problem; ERRSTRING is a string describing the specific
+   problem.  */
+   
+extern void _dl_signal_error (int errcode,
+                             const char *object,
+                             const char *errstring)
+     __attribute__ ((__noreturn__));
+
+/* Call OPERATE, catching errors from `dl_signal_error'.  If there is no
+   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING and
+   *OBJECT are set to the strings passed to _dl_signal_error, and the error
+   code passed is the return value.  */
+extern int _dl_catch_error (const char **errstring,
+                           const char **object,
+                           void (*operate) (void));
+
+
+/* Helper function for <dlfcn.h> functions.  Runs the OPERATE function via
+   _dl_catch_error.  Returns zero for success, nonzero for failure; and
+   arranges for `dlerror' to return the error details.  */
+extern int _dlerror_run (void (*operate) (void));
+
+
+/* Open the shared object NAME and map in its segments.
+   LOADER's DT_RPATH is used in searching for NAME.
+   If the object is already opened, returns its existing map.  */
+extern struct link_map *_dl_map_object (struct link_map *loader,
+                                       const char *name);
+
+/* Similar, but file found at REALNAME and opened on FD.
+   REALNAME must malloc'd storage and is used in internal data structures.  */
+extern struct link_map *_dl_map_object_from_fd (const char *name,
+                                               int fd, char *realname);
+
+/* Cache the locations of MAP's hash table.  */
+extern void _dl_setup_hash (struct link_map *map);
+
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+   referred to by UNDEF.  *SYM is the symbol table entry containing the
+   reference; it is replaced with the defining symbol, and the base load
+   address of the defining object is returned.  SYMBOL_SCOPE is the head of
+   the chain used for searching.  REFERENCE_NAME should name the object
+   containing the reference; it is used in error messages.  If NOSELF is
+   nonzero, them *SYM itself cannot define the value; another binding must
+   be found.  */
+extern Elf32_Addr _dl_lookup_symbol (const char *undef_name,
+                                    const Elf32_Sym **ref,
+                                    struct elf_resolve *symbol_scope,
+                                    const char *reference_name,
+                                    int noself);
+
+
+/* List of objects currently loaded.  */
+extern struct link_map *_dl_loaded;
+
+/* Tail of that list which were loaded at startup.  */
+extern struct link_map *_dl_startup_loaded;
+
+/* Allocate a `struct link_map' for a new object being loaded,
+   and enter it into the _dl_loaded list.  */
+extern struct link_map *_dl_new_object (char *realname, const char *libname,
+                                       int type);
+
+/* Relocate the given object (if it hasn't already been).
+   If LAZY is nonzero, don't relocate its PLT.  */
+extern void _dl_relocate_object (struct link_map *map, int lazy);
+
+/* Return the address of the next initializer function not yet run.
+   When there are no more initializers to be run, this returns zero.
+   The functions are returned in the order they should be called.  */
+extern Elf32_Addr _dl_init_next (void);
+
+/* Call the finalizer functions of all shared objects whose
+   initializer functions have completed.  */
+extern void _dl_fini (void);
+
+/* The dynamic linker calls this function before and having changing
+   any shared object mappings.  The `r_state' member of `struct r_debug'
+   says what change is taking place.  This function's address is
+   the value of the `r_brk' member.  */
+extern void _dl_r_debug_state (void);
+
+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(char * libname, int);
+
+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);
+
+
+
+#endif /* link.h */
diff --git a/gnu/libexec/ld.so/ld.so/mips/string.h b/gnu/libexec/ld.so/ld.so/mips/string.h
new file mode 100644 (file)
index 0000000..2728fd6
--- /dev/null
@@ -0,0 +1,303 @@
+#ifndef _DL_STRING_H_
+#define _DL_STRING_H_
+
+#include <sys/types.h> /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char *_dl_strcpy (char *dest, const char *src);
+extern inline char *_dl_strncpy (char *dest, const char *src, size_t count);
+extern inline char *_dl_strcat (char *dest, const char *src);
+extern inline char *_dl_strncat (char *dest, const char *src, size_t count);
+extern inline int _dl_strcmp (const char *cs, const char *ct);
+extern inline int _dl_strncmp (const char *cs, const char *ct, size_t count);
+extern inline char *_dl_strchr (const char *s, int c);
+extern inline char *_dl_strrchr (const char *s, int c);
+extern inline size_t _dl_strspn (const char *cs, const char *ct);
+extern inline size_t _dl_strcspn (const char *cs, const char *ct);
+extern inline char *_dl_strpbrk (const char *cs, const char *ct);
+extern inline char *_dl_strstr (const char *cs, const char *ct);
+extern inline size_t _dl_strlen (const char *s);
+extern inline char *_dl_strtok (char *s, const char *ct);
+extern inline void *_dl_memcpy (void *to, const void *from, size_t n);
+extern inline void *_dl_memmove (void *dest, const void *src, size_t n);
+extern inline int _dl_memcmp (const void *cs, const void *ct, size_t count);
+extern inline void *_dl_memchr (const void *cs, int c, size_t count);
+extern inline void *_dl_memset (void *s, int c, size_t count);
+
+/* Make sure we are using our inline version.  */
+#define strlen(s) _dl_strlen(s)
+
+extern inline char *
+_dl_strcpy (char *dest, const char *src)
+{
+  char *xdest = dest;
+
+  while ((*dest++ = *src++) != '\0')
+    ;
+  return xdest;
+}
+
+extern inline char *
+_dl_strncpy (char *dest, const char *src, size_t n)
+{
+  char *xdest = dest;
+
+  if (n == 0)
+    return xdest;
+
+  while ((*dest = *src++) != '\0')
+    if (--n == 0)
+      break;
+  return xdest;
+}
+
+extern inline char *
+_dl_strcat (char *dest, const char *src)
+{
+  char *xdest = dest;
+
+  while (*dest)
+    dest++;
+  while ((*dest++ = *src++) != '\0')
+    ;
+
+  return xdest;
+}
+
+extern inline char *
+_dl_strncat (char *dest, const char *src, size_t count)
+{
+  char *xdest = dest;
+
+  if (count)
+    {
+      while (*dest)
+       dest++;
+      while ((*dest++ = *src++) != '\0')
+       if (--count == 0)
+         break;
+    }
+
+  return xdest;
+}
+
+extern inline int
+_dl_strcmp (const char *cs, const char *ct)
+{
+  char c;
+
+  while ((c = *cs++) == *ct++)
+    if (c == 0)
+      return 0;
+  return c - *--ct;
+}
+
+extern inline int
+_dl_strncmp (const char *cs, const char *ct, size_t count)
+{
+  char c;
+
+  if (!count)
+    return 0;
+
+  while ((c = *cs++) == *ct++)
+    if (c == 0 || --count == 0)
+      return 0;
+  return c - *--ct;
+}
+
+extern inline char *
+_dl_strchr (const char *s, int c)
+{
+  const char ch = c;
+
+  for (; *s != ch; ++s)
+    if (*s == '\0')
+      return NULL;
+  return (char *) s;
+}
+
+extern inline char *
+_dl_strrchr (const char * s, int c)
+{
+  char *res = NULL;
+  const char ch = c;
+
+  for (;; ++s)
+    {
+      if (*s == ch)
+       res = (char *) s;
+      if (*s == '\0')
+       break;
+    }
+  return res;
+}
+
+extern inline size_t
+_dl_strspn (const char *s, const char *accept)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = accept; *a != '\0'; ++a)
+       if (*p == *a)
+         break;
+      if (*a == '\0')
+       return count;
+      ++count;
+    }
+
+  return count;
+}
+
+extern inline size_t
+_dl_strcspn (const char *s, const char *reject)
+{
+  const char *p;
+  const char *a;
+  size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = reject; *a != '\0'; ++a)
+       if (*p == *a)
+         return count;
+      ++count;
+    }
+
+  return count;
+}
+
+extern inline char *
+_dl_strpbrk (const char *cs, const char *ct)
+{
+  const char *sc1, *sc2;
+
+  for (sc1 = cs; *sc1 != '\0'; ++sc1)
+    for (sc2 = ct; *sc2 != '\0'; ++sc2)
+      if (*sc1 == *sc2)
+       return (char *) sc1;
+  return NULL;
+}
+
+extern inline char *
+_dl_strstr (const char *cs, const char *ct)
+{
+  const char *p;
+
+  for (;; cs++)
+    {
+      for (p = ct; *p == *cs; p++, cs++)
+       if (*p == 0)
+         return (char *) cs - (p - ct);
+      cs -= p - ct;
+      if (*cs == 0)
+       return NULL;
+    }
+}
+
+extern inline size_t
+_dl_strlen (const char *s)
+{
+  const char *sc;
+
+  for (sc = s; *sc != '\0'; ++sc)
+    ;
+  return sc - s;
+}
+
+extern char * ___strtok;
+
+extern inline char *
+_dl_strtok(char * s,const char * ct)
+{
+  char *sbegin, *send;
+
+  sbegin = s ? s : ___strtok;
+  if (!sbegin)
+    return NULL;
+  sbegin += _dl_strspn (sbegin, ct);
+  if (*sbegin == '\0')
+    {
+      ___strtok = NULL;
+      return NULL;
+    }
+  send = _dl_strpbrk (sbegin, ct);
+  if (send && *send != '\0')
+    *send++ = '\0';
+  ___strtok = send;
+  return sbegin;
+}
+
+extern inline void *
+_dl_memcpy (void *to, const void *from, size_t n)
+{
+  char *cto = to;
+  const char *cfrom = from;
+
+  while (n--)
+    *cto++ = *cfrom++;
+  return to;
+}
+
+extern inline void *
+_dl_memmove (void *dest, const void *src, size_t n)
+{
+  char *cdest = dest;
+  const char *csrc = src;
+
+  if (dest < src)
+    {
+      while (n--)
+       *cdest++ = *csrc++;
+    }
+  else
+    {
+      cdest += n;
+      csrc += n;
+      while (n--)
+       *--cdest = *--csrc;
+    }
+  return dest;
+}
+
+extern inline int
+_dl_memcmp (const void *cs, const void *ct, size_t count)
+{
+  const unsigned char *su1, *su2;
+
+  for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
+    if (*su1 != *su2)
+      return *su1 < *su2 ? -1 : 1;
+  return 0;
+}
+
+extern inline void *
+_dl_memchr (const void *cs, int c, size_t count)
+{
+  const unsigned char ch = c;
+  const unsigned char *s = cs;
+
+  for (; count != 0; ++s, count--)
+    if (*s == ch)
+      return (void *) s;
+  return NULL;
+}
+
+extern inline void *
+_dl_memset (void *s, int c, size_t count)
+{
+  char *cs = s;
+
+  while (count--)
+    *cs++ = c;
+  return s;
+}
+
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/mips/syscall.h b/gnu/libexec/ld.so/ld.so/mips/syscall.h
new file mode 100644 (file)
index 0000000..0ff1fbe
--- /dev/null
@@ -0,0 +1,201 @@
+#ifdef USE_CACHE
+#include <sys/stat.h>
+#endif
+
+#include <sys/syscall.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 a bunch of syscalls that are required
+   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. */
+
+extern inline int
+_dl_exit (int status)
+{ 
+  register int __status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "syscall"
+                    : "=r" (__status)
+                    : "0" (SYS_exit), "r" (status)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  while(1);
+} 
+
+extern inline int
+_dl_open (const char* addr, unsigned int flags)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "syscall\n\t"
+                   "beq   $7,$0,1f\n\t"
+                   "li    $2,-1\n\t"
+                   "1:"
+                    : "=r" (status)
+                    : "0" (SYS_open), "r" (addr), "r" (flags)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+extern inline int
+_dl_close (int fd)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "syscall\n\t"
+                   "beq   $7,$0,1f\n\t"
+                   "li    $2,-1\n\t"
+                   "1:"
+                    : "=r" (status)
+                    : "0" (SYS_close), "r" (fd)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+extern inline int
+_dl_write (int fd, const char* buf, int len)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "move  $6,%4\n\t"
+                    "syscall\n\t"
+                   "beq   $7,$0,1f\n\t"
+                   "li    $2,-1\n\t"
+                   "1:"
+                    : "=r" (status)
+                    : "0" (SYS_write), "r" (fd), "r" (buf), "r" (len)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+extern inline int
+_dl_read (int fd, const char* buf, int len)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "move  $6,%4\n\t"
+                    "syscall\n\t"
+                   "beq   $7,$0,1f\n\t"
+                   "li    $2,-1\n\t"
+                   "1:"
+                    : "=r" (status)
+                    : "0" (SYS_read), "r" (fd), "r" (buf), "r" (len)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+extern inline int
+_dl_mmap (void *addr, unsigned int size, unsigned int prot,
+          unsigned int flags, int fd, unsigned int f_offset)
+{ 
+  register int malloc_buffer __asm__ ("$2");
+  __asm__ volatile ("addiu $29,-40\n\t"
+                    "move  $6,%2\n\t"
+                    "move  $7,%3\n\t"
+                   "sw    %4,16($29)\n\t"
+                   "sw    %5,20($29)\n\t"
+#ifdef MIPSEL
+                   "li    $4,197\n\t"
+                    "li    $5,0\n\t"
+                   "sw    %6,24($29)\n\t"
+                   "sw    $0,28($29)\n\t"
+                   "sw    %7,32($29)\n\t"
+                   "sw    $0,36($29)\n\t"
+#endif
+#ifdef MIPSEB
+                    "li    $4,0\n\t"
+                   "li    $5,197\n\t"
+                   "sw    %6,24($29)\n\t"
+                   "sw    $0,28($29)\n\t"
+                   "sw    $0,32($29)\n\t"
+                   "sw    %7,36($29)\n\t"
+#endif
+                    "syscall\n\t"
+                   "addiu $29,40"
+                    : "=r" (malloc_buffer)
+                    : "0" (SYS___syscall), "r" (addr), "r" (size), "r" (prot),
+                     "r" (flags), "r" (fd), "r" (f_offset)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return malloc_buffer;
+} 
+
+extern inline int
+_dl_mprotect (const void *addr, int size, int prot)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "move  $6,%4\n\t"
+                    "syscall"
+                    : "=r" (status)
+                    : "0" (SYS_mprotect), "r" (addr), "r" (size), "r" (prot)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+#ifdef USE_CACHE
+extern inline int
+_dl_stat (const char *addr, struct stat *sb)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "syscall"
+                    : "=r" (status)
+                    : "0" (SYS_stat), "r" (addr), "r" (sb)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+
+extern inline int
+_dl_munmap (const void *addr, unsigned int size)
+{ 
+  register int status __asm__ ("$2");
+  __asm__ volatile ("move  $4,%2\n\t"
+                    "move  $5,%3\n\t"
+                    "syscall"
+                    : "=r" (status)
+                    : "0" (SYS_munmap), "r" (addr), "r" (size)
+                    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+                    "$10","$11","$12","$13","$14","$15","$24","$25");
+  return status;
+} 
+#endif
+
+/* 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)
+{
+  unsigned int uid, euid, gid, egid;
+
+  __asm__ volatile ("move $2,%1; syscall; move %0,$2"
+                    : "=r" (uid) : "r" (SYS_getuid) : "$2");
+  __asm__ volatile ("move $2,%1; syscall; move %0,$2"
+                    : "=r" (euid) : "r" (SYS_geteuid) : "$2");
+  __asm__ volatile ("move $2,%1; syscall; move %0,$2"
+                    : "=r" (gid) : "r" (SYS_getgid) : "$2");
+  __asm__ volatile ("move $2,%1; syscall; move %0,$2"
+                    : "=r" (egid) : "r" (SYS_getegid) : "$2");
+
+       return (uid == euid && gid == egid);
+}
diff --git a/gnu/libexec/ld.so/ld.so/mips/sysdep.h b/gnu/libexec/ld.so/ld.so/mips/sysdep.h
new file mode 100644 (file)
index 0000000..52d3f87
--- /dev/null
@@ -0,0 +1,75 @@
+
+/* 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) \
+       asm("   addiu   %0,$29,328" : "=r" (ARGVP))
+
+/* Get the address of the Global offset table.  This must be absolute,
+   not relative. This is already set up on mips  */
+#define GET_GOT(X)
+
+/*                      
+ * Calculate how much off the link address we are loaded.
+ */                             
+static inline Elf32_Addr
+elf_machine_load_offset (void)     
+{ 
+  Elf32_Addr addr;                  
+  asm ("        .set noreorder\n"
+       "        la %0, here\n"          
+       "        bltzal $0, here\n"
+       "        nop\n"          
+       "here:   subu %0, $31, %0\n"     
+       "        .set reorder\n"
+       : "=r" (addr));          
+  return addr;
+}                               
+
+/* 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) \
+       if(ELF32_R_TYPE((RELP)->r_info) == R_MIPS_REL32) { \
+               if (ELF32_ST_BIND ((SYMBOL)->st_info) == STB_LOCAL \
+                  && (ELF32_ST_TYPE ((SYMBOL)->st_info) == STT_SECTION \
+                   || ELF32_ST_TYPE ((SYMBOL)->st_info) == STT_NOTYPE)) { \
+                       *(REL) += (LOAD); \
+               } \
+               else { \
+                       *(REL) = (LOAD) + (SYMBOL)->st_value; \
+               } \
+       }
+
+/* Transfer control to the user's application, once the dynamic loader
+   is done.  t9 has to contain the entry (link) address */
+
+#define START()                                        \
+  __asm__ volatile ("move  $25, %0\n\t"                \
+                   "move  $29, %1\n\t"         \
+                   "jr  $25"                   \
+                   : : "r" (_dl_elf_main), "r" (stack));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_MIPS
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "mips"
+
+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 mips.  */
+#define do_rem(result, n, base)  ((result) = (n) % (base))
diff --git a/gnu/libexec/ld.so/ld.so/readelflib1.c b/gnu/libexec/ld.so/ld.so/readelflib1.c
new file mode 100644 (file)
index 0000000..2fad8ec
--- /dev/null
@@ -0,0 +1,470 @@
+/* Load an ELF sharable library into memory.
+
+   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
+
+
+/* This file contains the helper routines to load an ELF sharable
+   library into memory and add the symbol table info to the chain. */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include "hash.h"
+#include "sysdep.h"
+#include <unistd.h>
+#include "syscall.h"
+#include "string.h"
+#ifdef USE_CACHE
+#include "../config.h"
+#endif
+
+extern char *_dl_progname;
+extern _dl_runtime_resolve(void);
+
+#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 stat st;
+  header_t *header;
+
+  if (_dl_cache_addr != NULL)
+    return -1;
+
+  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_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
+  {
+    _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+    goto fail;
+  }
+
+  if (_dl_memcmp (header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
+  {
+    _dl_fdprintf(2, "%s: cache '%s' has wrong version\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;
+
+  _dl_munmap (_dl_cache_addr, _dl_cache_size);
+  _dl_cache_addr = NULL;
+
+  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(struct dyn_elf * dpnt,
+       char * full_libname){
+  char * pnt, *pnt1, *pnt2;
+  struct elf_resolve * tpnt, *tpnt1;
+  char mylibname[1024];
+  char * libname;
+
+  _dl_internal_error_number = 0;
+  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. */
+
+  if (libname != full_libname) {
+    tpnt1 = _dl_load_elf_shared_library(full_libname, 0);
+    if (tpnt1)
+      return tpnt1;
+    goto goof;
+  }
+
+  /* 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 != ';') *pnt2++ = *pnt1++;
+      if(pnt2[-1] != '/') *pnt2++ = '/';
+      pnt = libname;
+      while(*pnt) *pnt2++  = *pnt++;
+      *pnt2++ = 0;
+      tpnt1 = _dl_load_elf_shared_library(mylibname, 0);
+      if(tpnt1) return tpnt1;
+      if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
+    }
+  }
+
+#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 &&
+         _dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
+         (tpnt1 = _dl_load_elf_shared_library(strs+libent[i].liboffset, 0)))
+       return tpnt1;
+    }
+  }
+#endif
+
+  /* Check in rpath directories */
+  for(; dpnt; dpnt = dpnt->next) {
+    tpnt = dpnt->dyn;
+    pnt1 = (char *) tpnt->dynamic_info[DT_RPATH];
+    if(pnt1) {
+      pnt1 += (unsigned int) tpnt->loadoffs + tpnt->dynamic_info[DT_STRTAB];
+      while(*pnt1){
+       pnt2 = mylibname;
+       while(*pnt1 && *pnt1 != ':') *pnt2++ = *pnt1++;
+       if(pnt2[-1] != '/') *pnt2++ = '/';
+       pnt = libname;
+       while(*pnt) *pnt2++  = *pnt++;
+       *pnt2++ = 0;
+       tpnt1 = _dl_load_elf_shared_library(mylibname, 0);
+       if(tpnt1) return tpnt1;
+       if(*pnt1 == ':') pnt1++;
+      }
+    }
+  }
+
+  /* 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(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(mylibname, 0);
+  if (tpnt1) return tpnt1;
+
+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.
+ */
+
+struct elf_resolve * _dl_load_elf_shared_library(char * libname, int flag){
+  Elf32_Ehdr * epnt;
+  unsigned int dynamic_addr = 0;
+  unsigned int dynamic_size = 0;
+  Elf32_Dyn * dpnt;
+  struct elf_resolve * tpnt;
+  Elf32_Phdr * ppnt;
+  int piclib;
+  char * status;
+  int flags;
+  char header[4096];
+  int dynamic_info[DT_NUM + DT_MDEP];
+  int * lpnt;
+  unsigned int libaddr;
+  unsigned int liboffs;
+  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;
+
+  libaddr = 0;
+  liboffs = 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 = (Elf32_Ehdr *) 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 = (Elf32_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_COPY;
+  if(!piclib) flags|=MAP_FIXED;
+  
+  status = (char *) _dl_mmap((char *) (piclib?0:minvma),
+                         maxvma-minvma, 
+                         PROT_NONE, 
+                         flags | MAP_ANON, -1,
+                         0);
+  if(_dl_mmap_check_error(status)) {
+    _dl_fdprintf(2, "%s: can't map 'zero'\n", _dl_progname);
+    _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+    _dl_close(infile);
+     return NULL;
+  };
+  libaddr=(unsigned int)status;
+  liboffs = libaddr - minvma;
+  flags|=MAP_FIXED;
+  
+  /* Get the memory to store the library */
+  ppnt = (Elf32_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 *) (libaddr - minvma +
+                                            (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;
+       };
+       
+       if(!piclib) status = 0;
+       
+       /* Pad the last page with zeros. */
+       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 zerofill if
+   there are any pages left over that are not mapped as part of the file */
+
+       map_size = (ppnt->p_vaddr - minvma + ppnt->p_filesz + 0xfff) & 0xfffff000;
+       if(map_size < ppnt->p_vaddr - minvma + ppnt->p_memsz)
+         status = (char *) _dl_mmap((char *) map_size + libaddr, 
+                           ppnt->p_vaddr - minvma + ppnt->p_memsz - map_size,
+                           LXFLAGS(ppnt->p_flags),
+                           flags | MAP_ANON, -1, 0);
+      } else
+       status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + 
+                                  libaddr - minvma, 
+                         ((ppnt->p_vaddr - minvma) & 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) libaddr = 0;
+
+  dynamic_addr -= (unsigned int) minvma;
+  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 = (Elf32_Dyn *) dynamic_addr;
+
+  _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
+  while(dpnt->d_tag != DT_NULL) { 
+    if(dpnt->d_tag < DT_NUM) { 
+      dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+    }
+    else if(dpnt->d_tag  >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) {
+      dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val;
+    }
+    if(dpnt->d_tag == DT_TEXTREL)
+      dynamic_info[DT_TEXTREL] = 1;
+    dpnt++;
+  }
+  dynamic_size = dpnt - (Elf32_Dyn *) dynamic_addr;
+
+  tpnt = _dl_add_elf_hash_table(libname, (char *)libaddr, (char *)liboffs,
+                               dynamic_info, dynamic_addr, dynamic_size);
+
+  tpnt->ppnt = (Elf32_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)liboffs));
+    lpnt[0] = (int)_dl_runtime_resolve;
+    if(lpnt[1] & 0x80000000)
+      lpnt[1] = (Elf32_Addr) ((unsigned) tpnt | 0x80000000);
+  };
+  
+  return tpnt;
+}
+
diff --git a/gnu/libexec/ld.so/ld.so/sparc/Makefile b/gnu/libexec/ld.so/ld.so/sparc/Makefile
new file mode 100644 (file)
index 0000000..6f5ba56
--- /dev/null
@@ -0,0 +1,49 @@
+include ../../Version.mk
+include ../../Config.mk
+
+CC = $(ELFCC)
+AS = $(ELFAS)
+LD = $(ELFLD)
+
+CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops
+
+../%.o: %.S
+       $(CC) $(CFLAGS) -c $< -o $@
+../%.o: %.c
+       $(CC) $(CFLAGS) -c $< -o $@
+
+SRC1S = resolve.S
+SRC2S = elfinterp.c
+
+SRCS   = $(SRC1S) $(SRC2S)
+OBJ1S  = $(SRC1S:.S=.o)
+OBJ2S  = $(SRC2S:.c=.o)
+OBJS   = $(OBJ1S) $(OBJ2S)
+
+DLINK_OBJS:= $(addprefix ../, $(OBJS))
+
+lib:: $(DLINK_OBJS)
+
+obj: $(DLINK_OBJS)
+
+asm: $(ASMS)
+
+realclean::
+       $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~
+
+clean::
+       $(RM) -f core *.o *.a *.s *.i tmp_make *~
+
+depend::
+       $(CC) $(CFLAGS) -M $(SRCS) | \
+               sed -e 's,^[    ]*\(.*\.o\)[    ]*:,../\1:,' > .depend
+#      $(MAKE) subdir TARGET=depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
diff --git a/gnu/libexec/ld.so/ld.so/sparc/elfinterp.c b/gnu/libexec/ld.so/ld.so/sparc/elfinterp.c
new file mode 100644 (file)
index 0000000..cb1bfe2
--- /dev/null
@@ -0,0 +1,339 @@
+/* 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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef IBCS_COMPATIBLE
+#include <ibcs/unistd.h>
+#else
+#include <linux/unistd.h>
+#endif
+#include <fcntl.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "sysdep.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) {
+       _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_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(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 */
+
+#ifndef BROKEN_LINKER
+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++;
+      };
+    };
+      _dl_memcpy((char *) symtab[symtab_index].st_value, 
+                 (char *) symbol_addr, 
+                 symtab[symtab_index].st_size);
+  };
+  return goof;
+}
+#endif
+
+
diff --git a/gnu/libexec/ld.so/ld.so/sparc/resolve.S b/gnu/libexec/ld.so/ld.so/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/gnu/libexec/ld.so/ld.so/sparc/string.h b/gnu/libexec/ld.so/ld.so/sparc/string.h
new file mode 100644 (file)
index 0000000..3e6e099
--- /dev/null
@@ -0,0 +1,326 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+/* string.h: External definitions for optimized assembly string
+             routines for the Linux Kernel.
+
+   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+   Adapted for linux ELF dynamic loader by Eric Youngdale(eric@aib.com).
+*/
+
+
+#include <linux/types.h>       /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline size_t _dl_strlen(const char * s);
+extern inline int _dl_strcmp(const char * cs,const char * ct);
+extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count);
+extern inline char * _dl_strcpy(char * dest,const char *src);
+extern inline char * _dl_strncpy(char * dest,const char *src,size_t count);
+extern inline char * _dl_strcat(char * dest,const char * src);
+extern inline char * _dl_strncat(char * dest,const char * src,size_t count);
+extern inline char * _dl_strchr(const char * s,char c);
+extern inline char * _dl_strpbrk(const char * cs,const char * ct);
+extern inline size_t _dl_strspn(const char * cs, const char * ct);
+extern inline char * _dl_strtok(char * s,const char * ct);
+extern inline void * _dl_memset(void * s,char c,size_t count);
+extern inline void * _dl_memcpy(void * to, const void * from, size_t n);
+extern inline void * _dl_memmove(void * dest,const void * src, size_t n);
+extern inline int _dl_memcmp(const void * cs,const void * ct,size_t count);
+
+extern __inline__ size_t _dl_strlen(const char * s1)
+{
+       int count = 0;
+       while( *s1++ != '\0')
+       {
+               count++;
+       }
+
+       return count;;
+}
+
+extern __inline__ int _dl_strcmp(const char * s1, 
+                                 const char * s2)
+{
+       while( *s1 != '\0' && *s2 != '\0' )
+       {
+               if( *s1 != *s2 )
+                       return *s1 - *s2;
+               s1++;
+               s2++;
+       }
+
+       return *s1 - *s2;
+}
+
+extern __inline__ int _dl_strncmp(const char* str1, const char* str2, size_t strlen)
+{
+  register int retval=0;
+
+  __asm__("cmp %3, 0x0\n\t"
+         "be 2f\n\t"
+         "ldub [%2], %%g3\n\t"
+         "1: ldub [%1], %%g2\n\t"
+         "sub %%g2, %%g3, %0\n\t"
+         "cmp %0, 0x0\n\t"
+         "bne 2f\n\t"
+         "add %2, 0x1, %2\n\t"
+         "cmp %%g2, 0x0\n\t"
+         "be 2f\n\t"
+         "add %1, 0x1, %1\n\t"
+         "addcc %3, -1, %3\n\t"
+         "bne,a 1b\n\t"
+         "ldub [%2], %%g3\n\t"
+         "2: " :
+         "=r" (retval), "=r" (str1), "=r" (str2), "=r" (strlen) :
+         "0" (retval), "1" (str1), "2" (str2), "3" (strlen) :
+         "%g2", "%g3");
+
+  return retval;
+}
+
+
+extern __inline__ char *_dl_strcpy(char* dest, const char* source)
+{
+  register char tmp;
+  register char *retval;
+
+  __asm__("or %%g0, %2, %0\n\t"
+         "ldub [%1], %3\n\t"
+         "1: stb %3, [%2]\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne,a 1b\n\t"
+         "ldub [%1], %3\n\t" :
+         "=r" (retval), "=r" (source), "=r" (dest), "=r" (tmp) :
+         "0" (retval), "1" (source), "2" (dest), "3" (tmp));
+
+  return retval;
+}
+
+extern __inline__ char *_dl_strncpy(char *dest, const char *source, size_t cpylen)
+{
+  register char tmp;
+  register char *retval;
+
+  __asm__("or %%g0, %1, %0\n\t"
+         "1: cmp %4, 0x0\n\t"
+         "be 2f\n\t"
+         "ldub [%1], %3\n\t"
+         "add %1, 0x1, %1\n\t"
+         "stb %3, [%2]\n\t"
+         "sub %4, 0x1, %4\n\t"
+         "ba 1\n\t"
+         "add %2, 0x1, %2\n\t" :
+         "=r" (retval), "=r" (dest), "=r" (source), "=r"(tmp), "=r" (cpylen) :
+         "0" (retval), "1" (dest), "2" (source), 
+         "3" (tmp), "4" (cpylen));
+
+  return retval;
+}
+
+extern __inline__ char *_dl_strcat(char *dest, const char *src)
+{
+  register char *retval;
+  register char temp=0;
+
+  __asm__("or %%g0, %1, %0\n\t"
+         "1: ldub [%1], %3\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne,a 1b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "2: ldub [%2], %3\n\t"
+         "stb %3, [%1]\n\t"
+         "add %1, 0x1, %1\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne 2b\n\t"
+         "add %2, 0x1, %2\n\t" :
+         "=r" (retval), "=r" (dest), "=r" (src), "=r" (temp) :
+         "0" (retval), "1" (dest), "2" (src), "3" (temp));
+
+  return retval;
+}
+
+extern __inline__ char *_dl_strncat(char *dest, const char *src, size_t len)
+{
+  register char *retval;
+  register char temp=0;
+
+  __asm__("or %%g0, %1, %0\n\t"
+         "1: ldub [%1], %3\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne,a 1b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "2: ldub [%2], %3\n\t"
+         "stb %3, [%1]\n\t"
+         "add %1, 0x1, %1\n\t"
+         "add %3, -1, %3\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne 2b\n\t"
+         "add %2, 0x1, %2\n\t" :
+         "=r" (retval), "=r" (dest), "=r" (src), "=r" (len), "=r" (temp) :
+         "0" (retval), "1" (dest), "2" (src), "3" (len), "4" (temp));
+
+  return retval;
+}
+
+extern __inline__ char *_dl_strchr(const char *src, char c)
+{
+  register char temp=0;
+  register char *trick=0;
+
+  __asm__("1: ldub [%0], %2\n\t"
+         "cmp %2, %1\n\t"
+         "bne,a 1b\n\t"
+         "add %0, 0x1, %0\n\t"
+         "or %%g0, %0, %3\n\t" :
+         "=r" (src), "=r" (c), "=r" (temp), "=r" (trick), "=r" (src) :
+         "0" (src), "1" (c), "2" (temp), "3" (trick), "4" (src));
+
+  return trick;
+}
+
+extern __inline__ char *_dl_strpbrk(const char *cs, const char *ct)
+{
+  register char temp1, temp2;
+  register char *scratch;
+  register char *trick;
+
+  __asm__("or %%g0, %1, %4\n\t"
+         "1: ldub [%0], %2\n\t"
+         "2: ldub [%1], %3\n\t"
+         "cmp %3, %2\n\t"
+         "be 3f\n\t"
+         "nop\n\t"
+         "cmp %3, 0x0\n\t"
+         "bne 2b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "or %%g0, %4, %1\n\t"
+         "b 1b\n\t"
+         "add %0, 0x1, %0\n\t"
+         "or %%g0, %0, %5\n\t" :
+         "=r" (cs) :
+         "r" (ct), "r" (temp1), "r" (temp2), "r" (scratch), "r" (trick=0),
+         "0" (cs), "1" (ct));
+
+  return trick;
+
+}
+
+      
+extern __inline__ size_t _dl_strspn(const char *s, const char *accept)
+{
+  register char temp1, temp2;
+  register char* scratch;
+  register size_t trick;
+
+  __asm__("or %%g0, %1, %4\n\t"
+         "1: ldub [%0], %2\n\t"
+         "2: ldub [%1], %3\n\t"
+         "cmp %3, 0x0\n\t"
+         "be 3f\n\t"
+         "cmp %3, %2"
+         "bne 2b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "add %0, 0x1, %0\n\t"
+         "b 1b\n\t"
+         "add %5, 0x1, %5\n\t"
+         "3: or %%g0, %0, %4\n\t" :
+         "=r" (s) :
+         "r" (accept), "r" (temp1), "r" (temp2), 
+         "r" (scratch), "r" (trick=0), "0" (s));
+
+  return trick;
+
+}
+
+extern __inline__ void *_dl_memset(void *src, char c, size_t count)
+{
+  register char *retval;
+
+  retval = (char *) src;
+  while(count--)
+  {
+         *retval++ = c;
+  }
+}
+
+extern __inline__ void *_dl_memcpy(void *dest, const void *src, size_t count)
+{
+  register void *retval;
+  register char tmp;
+
+  __asm__("or %%g0, %1, %0\n\t"
+         "add %3, -1, %3\n\t"
+         "cmp %3, -1\n\t"
+         "be 2f\n\t"
+         "1: ldub [%2], %4\n\t"
+         "add %2, 0x1, %2\n\t"
+         "add %3, -1, %3\n\t"
+         "cmp %3, -1\n\t"
+         "stb %4, [%1]\n\t"
+         "bne 1b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "2: " :
+         "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
+         "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
+
+  return retval;
+}
+
+extern __inline__ void *_dl_memmove(void *dest, const void *src, size_t count)
+{
+  register void *retval;
+  register char tmp;
+
+  __asm__("or %%g0, %1, %1\n\t"
+         "add %3, -1, %3\n\t"
+         "cmp %3, -1\n\t"
+         "be 2f\n\t"
+         "1: ldub [%2], %4\n\t"
+         "add %2, 0x1, %2\n\t"
+         "add %3, -1, %3\n\t"
+         "cmp %3, -1\n\t"
+         "stb %4, [%1]\n\t"
+         "bne 1b\n\t"
+         "add %1, 0x1, %1\n\t"
+         "2: " :
+         "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) :
+         "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp));
+
+  return retval;
+}
+
+extern __inline__ int _dl_memcmp(const void *cs, const void *ct, size_t count)
+{
+  register int retval;
+  register unsigned long tmp1, tmp2;
+
+  __asm__("or %%g0, %1, %0\n\t"
+         "cmp %3, 0x0\n\t"
+         "ble,a 3f\n\t"
+         "or %%g0, %%g0, %0\n\t"
+         "1: ldub [%1], %4\n\t"
+         "ldub [%2], %5\n\t"
+         "cmp %4, %5\n\t"
+         "be,a 2f\n\t"
+         "add %1, 0x1, %1\n\t"
+         "bgeu 3f\n\t"
+         "or %%g0, 0x1, %0\n\t"
+         "b 3f\n\t"
+         "or %%g0, -1, %0\n\t"
+         "2: add %3, -1, %3\n\t"
+         "cmp %3, 0x0\n\t"
+         "bg 1b\n\t"
+         "add %2, 0x1, %2\n\t"
+         "or %%g0, %%g0, %0\n\t"
+         "3: " :
+         "=r" (retval) :
+         "r" (cs), "r" (ct), "r" (count), "r" (tmp1=0), "r" (tmp2=0));
+
+  return retval;
+}
+
+#endif
diff --git a/gnu/libexec/ld.so/ld.so/sparc/syscall.h b/gnu/libexec/ld.so/ld.so/sparc/syscall.h
new file mode 100644 (file)
index 0000000..2beb9f4
--- /dev/null
@@ -0,0 +1,249 @@
+
+extern inline volatile void _dl_exit(int status);
+extern inline volatile void _dl_close(int fd);
+extern inline int _dl_mmap(void * addr, unsigned int size,
+                                   unsigned int prot,
+                                   unsigned int flags, int fd,
+                                   unsigned int f_offset);
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+#define _dl_mmap_check_error(__res)    \
+       (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+extern inline int _dl_open(char * addr, unsigned int flags);
+extern inline int _dl_write(int fd, const char * buf, int len);
+extern inline int _dl_read(int fd, const char * buf, int len);
+extern inline int _dl_mprotect(const char * addr, int size, int prot);
+#include <sys/stat.h>
+extern inline int _dl_stat(char * filename, struct stat *st);
+extern inline int _dl_munmap(char * addr, int size);
+
+/* Here are the definitions for a bunch of syscalls that are required
+   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. */
+
+#ifdef SOLARIS_COMPATIBLE
+#include "/usr/include/sys/syscall.h"
+#endif
+
+extern inline volatile void _dl_exit(int status)
+{
+  int __res;
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "ta 8" \
+                    :  "=r" (__res) : "i" (__NR_exit),"r" ((long)(status)));
+}
+
+extern inline volatile void _dl_close(int fd)
+{
+    int status;
+
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                    : "=r" (status) \
+                    : "i" (__NR_close),"r" ((long)(fd))
+                    : "o0", "g1");
+    
+}
+
+extern inline int _dl_mmap(void * addr, unsigned int size,
+                                   unsigned int prot,
+                                   unsigned int flags, int fd,
+                                   unsigned int f_offset)
+{
+  int malloc_buffer;
+#ifdef SOLARIS_COMPATIBLE
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "sethi %%hi(0x80000000), %%o3\n\t" \
+                    "or %%o3, %5, %%o3\n\t" \
+                    "or %%g0, %6, %%o4\n\t" \
+                    "or %%g0, %7, %%o5\n\t" \
+                    "ta 8\n\t" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (malloc_buffer) : "0" (SYS_mmap),
+                   "r" (addr), "r" (size), "r" (prot), "r" (flags), 
+                   "r" (fd), "r" (f_offset)
+                    : "g1", "o0", "o1",  "o2", "o3",  "o4", "o5");
+#else
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "or %%g0, %5, %%o3\n\t" \
+                    "or %%g0, %6, %%o4\n\t" \
+                    "or %%g0, %7, %%o5\n\t" \
+                    "ta 8\n\t" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (malloc_buffer) : "0" (__NR_mmap),
+                   "r" (addr), "r" (size), "r" (prot), "r" (flags), 
+                   "r" (fd), "r" (f_offset)
+                    : "g1", "o0", "o1",  "o2", "o3",  "o4", "o5");
+#endif
+  return malloc_buffer;
+}
+
+
+extern inline int _dl_open(char * addr, unsigned int flags)
+{
+  int zfileno;
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, 0, %%o2\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (zfileno) \
+                   : "i" (__NR_open),"r" ((long)(addr)),"r" ((long)(flags))
+                    : "g1", "o0", "o1",  "o2");
+
+  return zfileno;
+}
+
+extern inline int _dl_write(int fd, const char * buf, int len)
+{
+  int status;
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (status) \
+                   : "i" (__NR_write),"r" ((long)(fd)),"r" ((long)(buf)),"r" ((long)(len))
+                    : "g1", "o0", "o1",  "o2");
+}
+
+
+extern inline int _dl_read(int fd, const char * buf, int len)
+{
+  int status;
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (status) \
+                   : "i" (__NR_read),"r" ((long)(fd)),"r" ((long)(buf)),"r" ((long)(len))
+                    : "g1", "o0", "o1",  "o2");
+}
+
+extern inline int _dl_mprotect(const char * addr, int size, int prot)
+{
+  int status;
+#ifdef SOLARIS_COMPATIBLE
+  __asm__ volatile ( "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "mov %1,%%g1\n"\
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (status) \
+                   : "i" (SYS_mprotect),"r" ((long)(addr)),"r" ((long)(size)),"r" ((long)(prot))
+                    : "g1", "o0", "o1",  "o2");
+#else
+  __asm__ volatile ( "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "or %%g0, %4, %%o2\n\t" \
+                    "mov %1,%%g1\n"\
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                   : "=r" (status) \
+                   : "i" (__NR_mprotect),"r" ((long)(addr)),"r" ((long)(size)),"r" ((long)(prot))
+                    : "g1", "o0", "o1",  "o2");
+#endif
+  return status;
+}
+
+extern inline int _dl_stat(char * filename, struct stat *st)
+{
+  int ret;
+#ifdef SOLARIS_COMPATIBLE
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                    : "=r" (ret) \
+                    : "i" (SYS_stat),"r" (filename),"r" (st)
+                    : "g1", "o0", "o1");
+
+
+#else
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                    : "=r" (ret) \
+                    : "i" (__NR_stat),"r" (filename),"r" (st)
+                    : "g1", "o0", "o1");
+
+
+#endif
+  return ret;
+}
+
+extern inline int _dl_munmap(char * addr, int size)
+{
+  int ret;
+  __asm__ volatile ("mov %1,%%g1\n"\
+                    "or %%g0, %2, %%o0\n\t" \
+                    "or %%g0, %3, %%o1\n\t" \
+                    "ta 8\n" \
+                    "mov %%o0, %0\n\t"
+                    : "=r" (ret) \
+                    : "i" (__NR_munmap),"r" ((long)(addr)),"r" ((long)(size))
+                    : "g1", "o0", "o1");
+
+  return ret;
+}
+
+/*
+ * 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)
+{
+  unsigned int uid, euid, gid, egid;
+  euid = egid = 0; /* So compiler does not warn us */
+
+#ifdef SOLARIS_COMPATIBLE
+  __asm__ volatile ("mov %2,%%g1\nta 8\n\t" 
+                    "mov %%o0, %0\n\t"
+                    "mov %%o1, %1\n\t"
+                    : "=r" (uid) , "=r" (euid) : "i" (SYS_getuid) : "g1");
+  __asm__ volatile ("mov %2,%%g1\nta 8\n\t"
+                    "mov %%o0, %0\n\t"
+                    "mov %%o1, %1\n\t"
+                    : "=r" (gid), "=r" (euid)  : "i" (__NR_getgid) : "g1");
+#else
+  __asm__ volatile ("mov %1,%%g1\nta 8\n\t" 
+                    "mov %%o0, %0\n\t"
+                    : "=r" (uid) : "i" (__NR_getuid) : "g1");
+  __asm__ volatile ("mov %1,%%g1\nta 8\n\t"
+                    "mov %%o0, %0\n\t"
+                    : "=r" (euid) : "i" (__NR_geteuid) : "g1");
+  __asm__ volatile ("mov %1,%%g1\nta 8\n\t"
+                    "mov %%o0, %0\n\t"
+                    : "=r" (gid) : "i" (__NR_getgid) : "g1");
+  __asm__ volatile ("mov %1,%%g1\nta 8\n\t"
+                    "mov %%o0, %0\n\t"
+                    : "=r" (egid) : "i" (__NR_getegid) : "g1");
+#endif
+
+    if(uid == euid && gid == egid)
+      return 1;
+    else
+      return 0;
+}
diff --git a/gnu/libexec/ld.so/ld.so/sparc/sysdep.h b/gnu/libexec/ld.so/ld.so/sparc/sysdep.h
new file mode 100644 (file)
index 0000000..064059a
--- /dev/null
@@ -0,0 +1,126 @@
+
+/*
+ * 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 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_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))
+
+
+
+/* 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.
+ */
+#define do_div(n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+       "sdiv %2,%3,%0\n\t" \
+        :"=r" (n),"=r" (__res):"r" (n),"r"(base)); __res; })
+
+
+#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; })
+
+/*
+ * 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/gnu/libexec/ld.so/ld.so/vsprintf.c b/gnu/libexec/ld.so/ld.so/vsprintf.c
new file mode 100644 (file)
index 0000000..a04c0a4
--- /dev/null
@@ -0,0 +1,238 @@
+/*  Adapted for ELF dynamic linker - Mitch
+ *
+ *  vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds and Lars Wirzenius
+ *
+ *  Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "hash.h"
+#include "string.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 SMALL  64              /* use 'abcdef' instead of 'ABCDEF' */
+
+static char * number(char * str, int num, int base, int size, int precision
+       ,int type)
+{
+       char c,sign,tmp[36];
+       const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       int i;
+
+       if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
+       if (type&LEFT) type &= ~ZEROPAD;
+       if (base<2 || base>36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ' ;
+       if (type&SIGN && num<0) {
+               sign='-';
+               num = -num;
+       } else
+               sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
+       if (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[(unsigned)num % base];
+               (unsigned)num /= base;
+       }
+       if (i>precision) precision=i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT)))
+               while(size-->0)
+                       *str++ = ' ';
+       if (sign)
+               *str++ = sign;
+       if (type&SPECIAL)
+               if (base==8)
+                       *str++ = '0';
+               else if (base==16) {
+                       *str++ = '0';
+                       *str++ = digits[33];
+               }
+       if (!(type&LEFT))
+               while(size-->0)
+                       *str++ = c;
+       while(i<precision--)
+               *str++ = '0';
+       while(i-->0)
+               *str++ = tmp[i];
+       while(size-->0)
+               *str++ = ' ';
+       return str;
+}
+
+int _dl_fdprintf(int fd, const char *fmt, ...)
+{
+       int len;
+       int i;
+       char * str;
+       char *s;
+       int *ip;
+
+       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 */
+       char buf[1024];
+       va_list args;
+
+       va_start(args, fmt);
+       for (str=buf ; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       *str++ = *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 == '*') {
+                       /* 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 == '*') {
+                               /* 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;
+               }
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       *str++ = ' ';
+                       *str++ = (unsigned char) va_arg(args, int);
+                       while (--field_width > 0)
+                               *str++ = ' ';
+                       break;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       len = _dl_strlen(s);
+                       if (precision < 0)
+                               precision = len;
+                       else if (len > precision)
+                               len = precision;
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       *str++ = ' ';
+                       for (i = 0; i < len; ++i)
+                               *str++ = *s++;
+                       while (len < field_width--)
+                               *str++ = ' ';
+                       break;
+
+               case 'o':
+                       str = number(str, va_arg(args, unsigned long), 8,
+                               field_width, precision, flags);
+                       break;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 8;
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str,
+                               (unsigned long) va_arg(args, void *), 16,
+                               field_width, precision, flags);
+                       break;
+
+               case 'x':
+                       flags |= SMALL;
+               case 'X':
+                       str = number(str, va_arg(args, unsigned long), 16,
+                               field_width, precision, flags);
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       str = number(str, va_arg(args, unsigned long), 10,
+                               field_width, precision, flags);
+                       break;
+
+               case 'n':
+                       ip = va_arg(args, int *);
+                       *ip = (str - buf);
+                       break;
+
+               default:
+                       if (*fmt != '%')
+                               *str++ = '%';
+                       if (*fmt)
+                               *str++ = *fmt;
+                       else
+                               --fmt;
+                       break;
+               }
+       }
+       *str = '\0';
+       _dl_write(fd, buf, str-buf);
+       return str-buf;
+}
+
diff --git a/gnu/libexec/ld.so/ldconfig/Makefile b/gnu/libexec/ld.so/ldconfig/Makefile
new file mode 100644 (file)
index 0000000..879737f
--- /dev/null
@@ -0,0 +1,11 @@
+#      $OpenBSD: Makefile,v 1.1 1996/09/18 08:16:06 pefo Exp $
+
+PROG=  ldconfig
+SRCS=  ldconfig.c readelf.c
+MAN=   ldconfig.8
+
+BINDIR=        /sbin
+
+.include <bsd.prog.mk>
+
+
diff --git a/gnu/libexec/ld.so/ldconfig/ld.so.conf b/gnu/libexec/ld.so/ldconfig/ld.so.conf
new file mode 100644 (file)
index 0000000..dfa65ed
--- /dev/null
@@ -0,0 +1,2 @@
+/usr/local/lib
+/usr/X11R6/lib
diff --git a/gnu/libexec/ld.so/ldconfig/ldconfig.8 b/gnu/libexec/ld.so/ldconfig/ldconfig.8
new file mode 100644 (file)
index 0000000..7bb663d
--- /dev/null
@@ -0,0 +1,142 @@
+.TH ldconfig 8 "30 March 1995"
+.SH NAME
+ldconfig \- determine run-time link bindings
+.SH SYNOPSIS
+ldconfig
+[
+.B \-DvnNX
+]
+.IR directory \ ...
+.PD 0
+.PP
+.PD
+ldconfig
+.B \-l
+[
+.B \-Dv
+]
+.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 directory
+.RI ( /usr/lib ).
+.I ldconfig
+checks the header and file names of the DLL's it encounters when
+determining which versions should have their links updated.
+.PP
+.I 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.
+.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 \-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
+
+/etc/ldconfig -v
+
+.RE
+will set up the correct links for the shared binaries and rebuild
+the cache.
+.TP
+On the command line
+.RS
+
+# /etc/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 /var/run/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/gnu/libexec/ld.so/ldconfig/ldconfig.c b/gnu/libexec/ld.so/ldconfig/ldconfig.c
new file mode 100644 (file)
index 0000000..bd32b11
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ * ldconfig - update shared library symlinks
+ *
+ * usage: ldconfig [-DvnNX] dir ...
+ *        ldconfig -l [-Dv] lib ...
+ *        ldconfig -p
+ *        -D: debug mode, don't update links
+ *        -v: verbose mode, print things as we go
+ *        -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
+ *        dir ...: directories to process
+ *        lib ...: libraries to link
+ *
+ * Copyright 1994, 1995 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 <dirent.h>
+#include <unistd.h>
+#include <a.out.h>
+#include <elf_abi.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "../config.h"
+
+char *___strtok = NULL;
+
+/* For SunOS */
+#ifndef PATH_MAX
+#include <limits.h>
+#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 *cachefile = LDSO_CACHE;  /* default cache file */
+void cache_print(void);
+void cache_dolib(char *dir, char *so, char *lib, int);
+void cache_rmlib(char *dir, char *so);
+void cache_write(void);
+
+char *readsoname(FILE *file);
+
+void warn(char *fmt, ...)
+{
+    va_list ap;
+
+    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;
+
+    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(char *str)
+{
+    char *ptr;
+    char *strdup(const char *);
+    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 */
+char *is_shlib(char *dir, char *name, int *type)
+{
+    char *good = NULL;
+    char *cp, *cp2;
+    FILE *file;
+    struct exec exec;
+    Elf32_Ehdr *elf_hdr;
+    struct stat statbuf;
+    char buff[1024];
+
+    /* see if name is of the form libZ.so.V */
+    if (strncmp(name, "lib", 3) == 0 &&
+       (cp = strstr(name, ".so.")) && cp[4])
+    {
+       /* find the start of the Vminor part, if any */
+       if ((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_ISLNK(statbuf.st_mode) && stat(buff, &statbuf))
+       {
+           if (verbose)
+               warn("%s is a stale symlink, removing", buff);
+           if (unlink(buff))
+               warn("can't unlink %s (%s), skipping", buff,
+                    strerror(errno));
+       }
+       else if (!S_ISREG(statbuf.st_mode))
+           warn("%s is not a regular file, skipping", buff, strerror(errno));
+       else
+       {
+           /* 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 DLL or ELF library */
+               if (fread(&exec, sizeof exec, 1, file) < 1)
+                   warn("can't read header from %s, skipping", buff);
+               else
+               {
+                   elf_hdr = (Elf32_Ehdr *) &exec;
+                   if (elf_hdr->e_ident[0] != 0x7f ||
+                       strncmp(&elf_hdr->e_ident[1], "ELF",3) != 0)
+                       warn("%s is not a DLL or ELF library, skipping", buff);
+                   else
+                   {
+                       if ((good = readsoname(file)) == NULL)
+                           good = xstrdup(name);
+                       *type = LIB_ELF;
+                   }
+               }
+               fclose(file);
+           }
+       }
+    }
+
+    return good;
+}
+
+/* update the symlink to new library */
+void link_shlib(char *dir, char *file, char *so)
+{
+    int change = -1;
+    char libname[1024];
+    char linkname[1024];
+    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 && !nolinks)
+    {
+       if (!lstat(linkname, &linkstat) && remove(linkname))
+           warn("can't unlink %s (%s)", linkname, strerror(errno));
+       else if (symlink(file, linkname))
+           warn("can't link %s to %s (%s)", linkname, file, strerror(errno));
+       else
+           change = 1;
+    }
+
+    /* some people like to know what we're doing */
+    if (verbose)
+       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 (*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 */
+    struct lib *next;          /* next library in list */
+};
+
+/* update all shared library links in a directory */
+void scan_dir(char *name)
+{
+    DIR *dir;
+    struct dirent *ent;
+    char *so;
+    struct lib *lp, *libs = NULL;
+    int libtype;
+
+    /* let 'em know what's going on */
+    if (verbose)
+       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)) == NULL)
+           continue;
+
+       if (!nocache)
+           cache_dolib(name, so, ent->d_name, libtype);
+
+       /* 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 (libcmp(ent->d_name, lp->name) > 0)
+               {
+                   /* let's use the new one */
+                   free(lp->name);
+                   lp->name = xstrdup(ent->d_name);
+               } 
+               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->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)
+    {
+       link_shlib(name, lp->name, lp->so);
+       if (strcmp(lp->name, lp->so) != 0)
+           cache_rmlib(name, lp->so);
+    }
+
+    /* 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 *cp = NULL;
+    FILE *file;
+    struct stat stat;
+
+    if ((file = fopen(LDSO_CONF, "r")) != NULL)
+    {
+       fstat(fileno(file), &stat);
+       cp = xmalloc(stat.st_size + 1);
+       fread(cp, 1, stat.st_size, file);
+       fclose(file);
+       cp[stat.st_size] = '\0';
+    }
+
+    return cp;
+}
+
+int main(int argc, char **argv)
+{
+    int i, c;
+    int nodefault = 0;
+    int printcache = 0;
+    char *cp, *dir, *so;
+    char *extpath;
+    int libtype;
+
+    prog = argv[0];
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "DvnNXlpf:")) != EOF)
+       switch (c)
+       {
+       case 'D':
+           debug = 1;          /* debug mode */
+           nocache = 1;
+           nolinks = 1;
+           verbose = 1;
+           break;
+       case 'v':
+           verbose = 1;        /* verbose 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;
+       default:
+           fprintf(stderr, "usage: %s [-DvnNX] dir ...\n", prog);
+           fprintf(stderr, "       %s -l [-Dv] lib ...\n", prog);
+           fprintf(stderr, "       %s -p\n", prog);
+           exit(EXIT_FATAL);
+           break;
+
+       /* THE REST OF THESE ARE UNDOCUMENTED AND MAY BE REMOVED
+          IN FUTURE VERSIONS. */
+       case 'f':
+           cachefile = optarg; /* alternate cache file */
+           break;
+       }
+
+    /* allow me to introduce myself, hi, my name is ... */
+    if (verbose)
+       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)) == 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);
+           }
+
+           /* everybody needs these, don't they? */
+           scan_dir("/usr/lib");
+       }
+
+       if (!nocache)
+           cache_write();
+    }
+
+    exit(EXIT_OK);
+}
+
+typedef struct liblist
+{
+    int flags;
+    int sooffset;
+    int liboffset;
+    char *soname;
+    char *libname;
+    int skip;
+    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(char *dir, char *so, char *lib, int libtype)
+{
+    char fullpath[PATH_MAX];
+    liblist_t *new_lib, *cur_lib;
+
+    magic.nlibs++;
+    sprintf(fullpath, "%s/%s", dir, lib);
+    new_lib = xmalloc(sizeof (liblist_t));
+    new_lib->flags = libtype;
+    new_lib->soname = xstrdup(so);
+    new_lib->libname = xstrdup(fullpath);
+    new_lib->skip = 0;
+
+    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_rmlib(char *dir, char *so)
+{
+    char fullpath[PATH_MAX];
+    liblist_t *cur_lib;
+
+    sprintf(fullpath, "%s/%s", dir, so);
+
+    for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
+    {
+        if (strcmp(cur_lib->soname, so) == 0 &&
+           strcmp(cur_lib->libname, fullpath) == 0 &&
+           !cur_lib->skip)
+       {
+           magic.nlibs--;
+           cur_lib->skip = 1;
+       }
+    }
+}
+
+void cache_write(void)
+{
+    int cachefd;
+    int stroffset = 0;
+    char tempfile[1024];
+    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));
+
+    write(cachefd, &magic, sizeof (header_t));
+
+    for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
+    {
+        if (!cur_lib->skip)
+       {
+           cur_lib->sooffset = stroffset;
+           stroffset += strlen(cur_lib->soname) + 1;
+           cur_lib->liboffset = stroffset;
+           stroffset += strlen(cur_lib->libname) + 1;
+           write(cachefd, cur_lib, sizeof (libentry_t));
+       }
+    }
+
+    for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
+    {
+        if (!cur_lib->skip)
+       {
+           write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1);
+           write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1);
+       }
+    }
+
+    close(cachefd);
+
+    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%2d - %s %s => %s\n", fd + 1, 
+       libent[fd].flags == LIB_DLL ? "DLL" : "ELF",
+       strs + libent[fd].sooffset, 
+       strs + libent[fd].liboffset);
+    }
+
+    munmap (c,st.st_size);
+}
+
diff --git a/gnu/libexec/ld.so/ldconfig/readelf.c b/gnu/libexec/ld.so/ldconfig/readelf.c
new file mode 100644 (file)
index 0000000..b15275e
--- /dev/null
@@ -0,0 +1,86 @@
+/* adapted from Eric Youngdale's readelf program */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <elf_abi.h>
+
+char *xstrdup(char *);
+
+char *readsoname(FILE *infile)
+{
+  Elf32_Ehdr *epnt;
+  Elf32_Phdr *ppnt;
+  int i;
+  char *header;
+  unsigned int dynamic_addr = 0;
+  unsigned int dynamic_size = 0;
+  int strtab_val = 0;
+  int soname_val = 0;
+  int loadaddr = -1;
+  int loadbase = 0;
+  Elf32_Dyn *dpnt;
+  struct stat st;
+  char *res = NULL;
+
+  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 = (Elf32_Ehdr *)header;
+  if ((int)(epnt+1) > (int)(header + st.st_size))
+    goto skip;
+
+  ppnt = (Elf32_Phdr *)&header[epnt->e_phoff];
+  if ((int)ppnt < (int)header ||
+      (int)(ppnt+epnt->e_phnum) > (int)(header + st.st_size))
+    goto skip;
+
+  for(i = 0; i < epnt->e_phnum; i++)
+  {
+    if (loadaddr == -1 && ppnt->p_vaddr != 0) 
+      loadaddr = (ppnt->p_vaddr & 0xfffff000) -
+       (ppnt->p_offset & 0xfffff000);
+    if(ppnt->p_type == 2)
+    {
+      dynamic_addr = ppnt->p_offset;
+      dynamic_size = ppnt->p_filesz;
+    };
+    ppnt++;
+  };
+    
+  dpnt = (Elf32_Dyn *) &header[dynamic_addr];
+  dynamic_size = dynamic_size / sizeof(Elf32_Dyn);
+  if ((int)dpnt < (int)header ||
+      (int)(dpnt+dynamic_size) > (int)(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;
+    if (dpnt->d_tag == DT_SONAME)
+      soname_val = dpnt->d_un.d_val;
+#define DT_MIPS_BASE_ADDRESS    0x70000006     /* XXX */
+    if (dpnt->d_tag == DT_MIPS_BASE_ADDRESS)
+      loadbase = dpnt->d_un.d_val;
+    dpnt++;
+  };
+
+  if (!strtab_val || !soname_val)
+    goto skip;
+  if (soname_val + strtab_val - loadbase < 0 ||
+      soname_val + strtab_val - loadbase >= st.st_size)
+    goto skip;
+
+  res = xstrdup((char *) (header - loadbase + strtab_val + soname_val));
+
+ skip:
+  munmap(header, st.st_size);
+
+  return res;
+}
+