summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2004-03-05 19:06:24 +0000
committerManuel Novoa III <mjn3@codepoet.org>2004-03-05 19:06:24 +0000
commit9c12805bf3341becb4ff647bdfbfe5318e379468 (patch)
tree4943c79b54b56abe992e1b274eb45a463a232e6d /sources
parentde40cc62a0d5c276d4628470cc5217a495d5afac (diff)
Make it possible to use the (modified) 0.9.24 ldso code. This is a
temporary work around for my openwrt stuff since the current (.26+) code still isn't working in some cases... for me at least.
Diffstat (limited to 'sources')
-rw-r--r--sources/uClibc-ldso-0.9.24.patch11861
1 files changed, 11861 insertions, 0 deletions
diff --git a/sources/uClibc-ldso-0.9.24.patch b/sources/uClibc-ldso-0.9.24.patch
new file mode 100644
index 000000000..ee65aa193
--- /dev/null
+++ b/sources/uClibc-ldso-0.9.24.patch
@@ -0,0 +1,11861 @@
+diff -urN uClibc/ldso-0.9.24/COPYRIGHT uClibc.ldso.24/ldso-0.9.24/COPYRIGHT
+--- uClibc/ldso-0.9.24/COPYRIGHT 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/COPYRIGHT 2001-04-23 12:43:53.000000000 -0500
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, David Engel,
++ * Hongjiu Lu and Mitch D'Souza
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. The name of the above contributors may not be
++ * used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/* Notice of general intent:
++ *
++ * The linux operating system generally contains large amounts of code
++ * that fall under the GNU General Public License, or GPL for short.
++ * This file contains source code that by it's very nature would always
++ * be linked with an application program, and because of this a GPL
++ * type of copyright on this file would place restrictions upon the
++ * distribution of binary-only commercial software. Since the goal of
++ * the Linux project as a whole is not to discourage the development and
++ * distribution of commercial software for Linux, this file has been
++ * placed under a more relaxed BSD-style of copyright.
++ *
++ * It is the general understanding of the above contributors that a
++ * program executable linked to a library containing code that falls
++ * under the GPL or GLPL style of license is not subject to the terms of
++ * the GPL or GLPL license if the program executable(s) that are supplied
++ * are linked to a shared library form of the GPL or GLPL library, and as
++ * long as the form of the shared library is such that it is possible for
++ * the end user to modify and rebuild the library and use it in
++ * conjunction with the program executable.
++ */
+diff -urN uClibc/ldso-0.9.24/Makefile uClibc.ldso.24/ldso-0.9.24/Makefile
+--- uClibc/ldso-0.9.24/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/Makefile 2003-11-06 16:38:45.000000000 -0600
+@@ -0,0 +1,52 @@
++# Makefile for uClibc
++#
++# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org>
++#
++# This program 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.
++#
++# 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 Library General Public License for more
++# details.
++#
++# You should have received a copy of the GNU Library General Public License
++# along with this program; if not, write to the Free Software Foundation, Inc.,
++# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++#
++# Derived in part from the Linux-8086 C library, the GNU C Library, and several
++# other sundry sources. Files within this library are copyright by their
++# respective copyright holders.
++
++TOPDIR=../
++include $(TOPDIR)Rules.mak
++
++ALL_SUBDIRS = ldso libdl
++
++
++all: headers
++ifeq ($(strip $(BUILD_UCLIBC_LDSO)),y)
++ $(MAKE) -C ldso;
++else
++ echo "Not building ld-uClibc"
++endif
++
++shared:
++ifeq ($(strip $(BUILD_UCLIBC_LDSO)),y)
++ $(MAKE) -C libdl;
++else
++ echo "Not building libdl"
++endif
++
++headers:
++ $(LN) -fs $(TOPDIR)../include/elf.h include/
++ $(LN) -fs ../ldso/$(TARGET_ARCH)/boot1_arch.h include/
++ $(LN) -fs ../ldso/$(TARGET_ARCH)/ld_syscalls.h include/
++ $(LN) -fs ../ldso/$(TARGET_ARCH)/ld_sysdep.h include/
++
++clean:
++ set -e ; for d in $(ALL_SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
++ -find . -name '*~' | xargs $(RM)
++ $(RM) include/elf.h include/boot1_arch.h include/ld_syscalls.h include/ld_sysdep.h
+diff -urN uClibc/ldso-0.9.24/README uClibc.ldso.24/ldso-0.9.24/README
+--- uClibc/ldso-0.9.24/README 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/README 2001-05-31 16:23:20.000000000 -0500
+@@ -0,0 +1,841 @@
++
++Apr 20, 2001 -- Manuel Novoa III
++
++Inital port for uClibc from debian ld.so_1.9.11-9.tar.gz.
++
++Removed a.out support.
++
++****************** original ld.so.lsm file **************************
++Begin3
++Title: Linux shared, dynamic linker and utilities.
++Version: 1.9.11
++Entered-date: 01MAY99
++Description: This package contains ld.so, ld-linux.so, ldconfig,
++ ldd and libdl.
++Keywords: dynamic linker, shared library, ld.so, ld-linux.so,
++ ldconfig, ldd, libdl
++Author: david@ods.com (David Engel)
++Maintained-by: david@ods.com (David Engel)
++Primary-site: tsx-11.mit.edu /pub/linux/packages/GCC
++ ld.so-1.9.11.tar.gz
++Alternate-site: sunsite.unc.edu /pub/Linux/GCC
++ ld.so-1.9.11.tar.gz
++Platform: Linux 2.0.0 or later.
++Copying-policy: Copyrighted but freely distributable.
++End
++*********************************************************************
++ Original README starts here
++*********************************************************************
++
++This package contains my ELF dynamic linkers (ld-linux.so.1), dynamic
++linker library (libdl.so.1) and utilities (ldconfig and ldd) for Linux.
++
++You need Linux kernel 2.0.0 or later with ELF support compiled in
++(i.e. not loaded as a module) to use this package.
++
++The dynamic linker is used to bootstrap programs and load shared
++libraries at startup. The dynamic linker library is used to
++dynamically load shared libraries after a program is running.
++Ldconfig is used to automatically update the symbolic links to shared
++libraries and build the cache file used by the dynamic linker. Ldd is
++used to list the shared libraries used by a program.
++
++Please see the included manual pages for further details.
++
++To install, simply run "sh instldso.sh" as root. Ready-to-go versions
++of all end-products are provided so nothing should need to be compiled
++or linked. If you are still using libc5 as your primary development
++library, you should use the "--devfiles" option when running
++instldso.sh to install the file needed to compile with libdl.
++
++ELF versions of gcc, binutils and libc are now required to compile
++everything, including the old, unsupported, a.out dynamic linker.
++Finally, an optimization level of O2 or higher must be used to compile
++ld-linux.so and libdl.so due the use of inline functions.
++
++Notable contributors to this package include Eric Youngdale, Peter
++MacDonald, Hongjiu Lu, Linus Torvalds, Lars Wirzenius, Mitch D'Souza,
++Rik Faith, Andreas Schwab and Adam Richter (not necessarily in that
++order).
++
++###################### IMPORTANT NOTICES #############################
++
++A.OUT SUPPORT:
++
++As of ld.so-1.9.0, the old, a.out dynamic loader is no longer
++officially supported. The code is still included and built, but I
++make no promises that it will work. I will accept patches for it,
++but they will not be tested by me.
++
++GLIBC (AKA LIBC6) SUPPORT:
++
++As of ld.so-1.9.0, the main focus of this package is to ease the
++transition to libc6. No significant, new features are expected to be
++added. If you need new features, switch to libc6.
++
++Except for libpthread.so, the sonames of the core libraries provided
++with libc6 have been chosen so they do not conflict with those
++provided by libc5 and ld.so. However, the current plan is not use
++new, nonconflicting sonames for other libraries such as ncurses and
++X11. This presents two problems. First, libraries using the same
++soname for both libc5 and libc6 can not be placed in the same
++directory. Second, the dynamic linkers need to make sure not to load
++a library for the wrong version of libc.
++
++The first problem is easy. Just move the old, libc5-based libraries
++to new directories (e.g. /lib/libc5-compat, /usr/lib/libc5-compat,
++etc.) and add those directories to /etc/ld.so.conf. Then install the
++new, libc6-based versions in the standard places.
++
++The second problem is more difficult. Ideally, the dynamic linkers
++would be changed to perform a complete dependency analysis on every
++library to be loaded to make sure the wrong versions aren't used.
++This approach doesn't seem worth the added complexity, especially
++since we now have symbol versioning for ELF libraries. Instead a
++simpler approach will be used, at least initially.
++
++Ldconfig has been modified to perform a (currently simple) dependency
++analysis on libraries and to store an indication in /etc/ld.so.cache
++of whether a library is for libc5, libc6 or an unknown libc. The
++dynamic linkers then only need to make a simple check at run-time to
++make sure they don't load the wrong version of a library.
++
++The dynamic linker for libc5 provided in this package, has already
++been modified to use the new information in /etc/ld.so.cache. For
++glibc versions 2.0.1 and earlier, the dynamic linker for libc6 needs
++the patch contained in glibc.patch. You should apply the patch and
++rebuild glibc before using the new ldconfig.
++
++As stated above, the dependency analysis currently done by ldconfig is
++rather simple. Basically, it looks for the sonames used by the
++various versions of libc, libm and libdl. For any approach using a
++dependency analysis such as this to work, it is very important that
++shared libraries be built with complete dependency information. This
++can be done by using the appropriate -l options when running 'gcc
++-shared'. For example, when building libfoo.so which depends on libc
++and libbar, you should add -lbar and -lc gcc command line.
++
++######################################################################
++
++Changes in version 1.9.11:
++
++ Fixed a bug in ld-linux.so where a reference to an
++ undefined symbol could cause a segfault.
++
++ Added a clarification for LD_PRELOAD to the ld.so manual
++ page and added a symlink for ld-linux.so (Bug#33123).
++
++ Don't install ldd for Debian except for the m68k arch
++ because glibc 2.1 now includes it (Bug#35458).
++
++Changes in version 1.9.10:
++
++ Changed ldconfig to issue a warning and not overwrite a
++ regular file with a symlink (Bug#30859).
++
++ Changed Debian packaging to conflict with and replace the
++ ldconfig package (Bug#29398).
++
++Changes in version 1.9.9:
++
++ Changed ld-linux.so and libdl.so to match glibc by not
++ allowing user preloads of system libraries into setu/gid
++ binaries unless the library itself is setuid.
++
++ Fixed problems in ld-linux.so on the sparc architecture
++ (Juan Cespedes).
++
++Changes in version 1.9.8:
++
++ Changed ldconfig to allow the expected type for all
++ libraries in a directory to be optionally specified
++ (Mark Phillips). See the ldconfig man page.
++
++ Changed ldconfig to use the same type names used in the
++ change above when the -p option is used.
++
++Changes in version 1.9.7:
++
++ Changed ldd for m68k to use /lib/ld.so.1 instead of
++ /lib/ld-linux.so.2.
++
++ Added support for dladdr to libdl.so (Eduard Gode).
++
++ Fixed a small memory leak in libdl.so (Richard Garnish).
++
++ Fixed a bug in ldconfig when the -l option was used on a
++ filename without a '/' in it.
++
++ Updated the man pages (Bug#6404, Bug#9721, Bug#10652,
++ Bug#13494 and Bug#14127). They could still use some work.
++
++ No longer install the info page since it's way out of date.
++
++ Fixed minor Debian packaging problems (Bug#13160,
++ Bug#15577 and Bug#19345).
++
++Changes in version 1.9.6:
++
++ Changed ldd to not use the glibc dynamic linker when run
++ on a libc5-based shared library.
++
++ Added a -q option to ldconfig which causes warnings not
++ to be printed (Bob Tinsley).
++
++ Dropped support for the Debian libdl1-dev package.
++
++ Changed ld-linux.so to be compilable with gcc 2.8.0 (Sven
++ Verdoolaege)
++
++Changes in version 1.9.5:
++
++ Fixed a bug in ldd where ld-linux.so.2 was not called
++ correctly when run on shared libraries.
++
++ Fixed a problem in the previous version where some
++ Makefiles were not architecture independent.
++
++Changes in version 1.9.4:
++
++ Fixed a bug in ld.so introduced in the previous version
++ which broke preloads.
++
++ Turned a.out support back on by default, at least for the
++ time being. There are no promises to keep it.
++
++Changes in version 1.9.3:
++
++ Fixed buffer overflow bugs in ld-linux.so and ld.so.
++
++ Changed the README file a little to clarify a couple of
++ things.
++
++ Changed ldconfig to chroot to the specified directory when
++ the new -r option is used (Bob Tinsley).
++
++Changes in version 1.9.2:
++
++ Removed /usr/local/lib from the default /etc/ld.so.conf
++ for Debian (Bug#8181).
++
++ Changed ldconfig to be 64-bit clean (H.J. Lu).
++
++Changes in version 1.9.1:
++
++ Changed ldconfig to try to determine which libc a
++ library is for even if it doesn't have an soname.
++
++ Fixed a bug in ldconfig where an older library using
++ the glibc naming convention would be used instead of
++ a newer library.
++
++ Changed to ld-linux.so and libdl.so to not require the
++ libc5 headers in order to compile.
++
++ Changed ldconfig and ldd to be compilable with either
++ libc5 or libc6.
++
++Changes in version 1.9.0:
++
++ Changed to not build the old, a.out dynamic loader by
++ default.
++
++ Changed instldso.sh to require the --force option to
++ make sure users read the README file.
++
++ Changed instldso.sh to not install the libdl.so
++ development files unless the --devfiles option is used.
++
++ Changed instldso.sh to not strip binaries and libraries
++ if the --no-strip option is used.
++
++ Changed the Debian packaging to put the development files
++ which conflict with glibc in a new libdl1-dev package.
++
++ Changed ldd to use the glibc dynamic linker, if it is
++ available, when run on a shared library.
++
++ Changed ld-linux.so to print the load addresses of
++ libraries, ala glibc, when run by ldd.
++
++ Changed ld-linux.so to allow the libraries listed in
++ LD_PRELOAD to be separated by white space in addition to
++ colons.
++
++ Changed ld-linux.so to load the libraries listed in
++ LD_PRELOAD for setu/gid programs as long as they can be
++ loaded securely.
++
++ Changed ldconfig to update the symlinks for the dynamic
++ linkers.
++
++ Changed ldconfig to try to determine if an ELF library is
++ intended for libc5 or libc6 and save the infomation in the
++ cache. The mechanism used is rather simplistic and may
++ need to be enhanced.
++
++ Changed ldconfig to print the type of ELF library when
++ printing the cache.
++
++ Changed ld-linux.so to only load ELF shared libraries for
++ use with libc5 or an unknown libc.
++
++Changes in version 1.8.10:
++
++ Fixed a bug in ldconfig where a symlink could be used
++ instead of a regular file.
++
++ Fixed a Debian packaging problem for the sparc
++ architecture.
++
++Changes in version 1.8.9:
++
++ Changed ldconfig to only cache the symlinks it creates.
++ This make the behavior of the dynamic linkers consistent
++ with how they would behave if a cache was not used.
++
++ Changed ldconfig to cache the symlinks that it finds but
++ use the name of the symlink as the soname instead of the
++ actual soname.
++
++Changes in version 1.8.8:
++
++ Minor documentation updates to reflect recent changes.
++
++ Changed ld.so and ld-linux.so to perform more complete
++ validation on ld.so.cache before using it.
++
++ Changed ldconfig to accept libraries with inconsistent
++ sonames since glibc is going to use them. A warning is
++ still printed in debug mode.
++
++ Changed the install script to not strip _dl_debug_state
++ from ld-linux.so since gdb needs it.
++
++ More sparc fixes (Derrick Brashear).
++
++ Changed ldconfig to not issue a warning when a linker
++ script disguised as a shared library is found.
++
++ Fixed a bug in ld-linux.so where some registers were
++ not preserved on the first call to a function causing
++ problems for non-C-like languages (Tim Renouf).
++
++ Fixed a bug in ld-linux.so where global variables were
++ not always mapped correctly across dynamically loaded
++ libraries (Mikihiko Nakao).
++
++ Converted to new Debian source packaging format (Shaya
++ Potter).
++
++Changes in version 1.8.6/7:
++
++ Never released as some unofficial patches used these
++ version numbers.
++
++Changes in version 1.8.5:
++
++ Fixed a bug in ld.so introduced in the previous changes.
++
++Changes in version 1.8.4:
++
++ Changed ldconfig to completely ignore symbolic links.
++
++ Changed ldconfig to issue the warning concerning an
++ inconsistent soname in non-verbose mode.
++
++ Changed ld-linux.so back to not keep ld.so.cache mapped
++ at all times.
++
++ Changed Debian packaging to compress man pages, strip all
++ binaries (Bug#5125) and include a shlibs file.
++
++Changes in version 1.8.3:
++
++ Changed ld-linux.so to process LD_PRELOAD before
++ /etc/ld.so.preload.
++
++ Fixed a Debian packaging problem where libdl might not
++ be available if other packages were upgraded at the same
++ time (Debian Bug#4728).
++
++ Changed ldd to always exit with status 1 if any errors
++ occur (Debian Bug#4188).
++
++ Fixed some minor problems in instldso.sh (Mike Castle and
++ Wolfgang Franke).
++
++ Changed ldconfig to issue a warning in verbose mode when
++ skipping a library because the soname doesn't match.
++
++ More sparc fixes (Miguel de Icaza).
++
++ Don't link with -N when building ld.so (Alan Modra).
++
++ Changed ld-linux.so to better support position-dependant
++ libraries (NIIBE Yutaka).
++
++Changes in version 1.8.2:
++
++ Added a texinfo file for ld.so and libdl (Michael
++ Deutschmann).
++
++ Minor sparc and installation changes (Elliot Lee).
++
++ Added multiple architecture support for Debian (Leland
++ Lucius).
++
++ Changed libdl to better support RTLD_NEXT (Eric
++ Youngdale). Note: the exact meaning of ETLD_NEXT is
++ still not clear in all cases.
++
++ Removed some libc dependencies from libdl. Still need
++ to remove malloc and free.
++
++Changes in version 1.8.1:
++
++ Changed ld.so to be compiled as ELF. This also means
++ that ELF support is now required. A.out support is
++ still optional.
++
++ Changed ld-linux.so and libdl.so to use the rpath in the
++ executable instead of in the invoking shared library.
++
++ More m68k fixes (Andreas Schwab).
++
++ Various sparc fixes (Miguel de Icaza).
++
++ Changed ldcnnfig to ignore libraries ending in '~'.
++
++ Changed ldconfig to allow alternative conf and cache
++ files to be specified on the command-line.
++
++ Changed libdl.so to work when dlsym is passed a NULL
++ handle pointer.
++
++Changes in version 1.8.0:
++
++ Changed ld-linux.so to be more liberal when checking to
++ see if a library is already loaded. This should avoid
++ the duplicate loading problem for programs linkeed with
++ the -rpath option.
++
++ Various m68k fixes (Andreas Schwab).
++
++ Changed ld.so to only use LD_AOUT_LIBRARY_PATH and
++ LD_AOUT_PRELOAD and ld-linux.so to only use
++ LD_LIBRARY_PATH and LD_PRELOAD. LD_ELF_LIBRARY_PATH
++ and LD_ELF_PRELOAD are no longer supported.
++
++ Changed ld-linux.so to allow debugging of shared and
++ dynamically loaded libraries (H.J. Lu, Andreas Schwab).
++
++ Changed ld-linux.so to preload ELF shared libraries
++ listed in /etc/ld.so.preload. This allows secure
++ preloads, even for setuid/setgid programs.
++
++ Changed ld-linux.so to keep ld.so.cache mapped at all
++ times.
++
++ Changed ldconfig to allow #-style comments in ld.so.conf.
++
++ Removed various compiler warnings (Richard Sladkey and
++ David Engel).
++
++ Changed ldd to work on ELF shared libraries. This may
++ need a little more work.
++
++Changes in version 1.7.14:
++
++ Changed ldconfig to recognize ELF shared libraries
++ generated by post-2.6 versions of ld (Andreas Schwab).
++
++ Changed ldconfig to not remove stale links that do not
++ have a version number since they may be needed by ld.
++
++Changes in version 1.7.13:
++
++ Fixed a problem in ld-linux.so where a program linked
++ with a shared library that was not used could result in
++ a segmentation fault (H.J. Lu).
++
++Changes in version 1.7.12:
++
++ Fixed a problem in libdl.so where the wrong library
++ could be marked as global when RTLD_GLOBAL was used
++ (Lars Heete).
++
++ Installed dlfcn.h with libdl.so instead of requiring
++ it to be supplied with libc.
++
++ Removed support for libldso.a since it was nearly
++ impossible to use anyway.
++
++ Changed ldd to detect when the program being checked
++ exited abnormally.
++
++Changes in version 1.7.11:
++
++ Changed ld.so and ld-linux.so to delete all variations
++ of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs,
++ This makes it harder for broken set[ug]id programs to be
++ compromised.
++
++ Fixed a problem in libdl.so where dlsym would not accept
++ the handle returned from dlopen(0, *).
++
++Changes in version 1.7.10:
++
++ Changed ld-linux.so and libdl.so to support RTLD_GLOBAL
++ (Eric Youngdale).
++
++Changes in version 1.7.9:
++
++ Fixed a problem in ld-linux.so in detecting when the
++ new user/group information is provided by the kernel.
++
++ Fixed a problem in ld-linux.so where a buffer could be
++ overflowed if a large number of libraries were loaded
++ (Thomas Moore).
++
++Changes in version 1.7.8:
++
++ Changed the Makefiles and install scripts to support
++ a.out- and ELF-only configurations.
++
++ Changed ld-linux.so to use the user/group information
++ provided by linux 1.3.23+ instead of making syscalls
++ to get it.
++
++ Changed libdl.so to support RTLD_NEXT (Glenn Fowler).
++
++ Changed libdl.so to only execute the fini sections
++ instead of completely closing libraries at exit (Glenn
++ Fowler).
++
++ Changed ld.so and ld-linux.so to print the required
++ cache version when a mismatch is detected.
++
++ Changed ld-linux.so to not require on /dev/zero (Ralph
++ Loader).
++
++ Minor m68k cleanups (Andreas Schwab).
++
++Changes in version 1.7.7:
++
++ Fixed problems compiling with recent 1.3.x kernels.
++
++ Changed ld-linux.so to not use MAP_DENYWRITE until the
++ permission issue regarding it is resolved.
++
++Changes in version 1.7.6:
++
++ Fixed a bug in ld-linux.so dealing with a zero-length
++ LD_{ELF_}PRELOAD.
++
++ Changed ld.so and ld-linux.so to truncate all variations
++ of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs.
++
++Changes in version 1.7.5:
++
++ Changed ldconfig to recognize libraries without any
++ version number (eg. libXYZ.so).
++
++ Changed ldconfig to not generate a corrupt cache when
++ the disk is full or other write errors occur.
++
++ Changed ld-linux.so to map files with MAP_DENYWRITE to
++ keep them from being changed while the file is in use
++ (Rick Sladkey).
++
++ Changed libdl to not overwrite the scope pointer of a
++ library if it was already loaded (H.J. Lu).
++
++ Changed ld-linux.so so gdb can be used on constructors
++ (Eric Youngdale).
++
++ Changed ldconfig to ignore ELF libraries where the soname
++ does not match the file name on the assumption that it is
++ a used at compile-time (eg. libcurses.so -> libncruses.so).
++
++Changes in version 1.7.4:
++
++ Changed ld-linux.so and libdl to use the appropriate
++ rpaths when searching for shared libraries (Eric
++ Youngdale).
++
++ Changed ld-linux.so to search rpath before using the
++ cache. This more closely conforms to the IBCS standard.
++
++Changes in version 1.7.3:
++
++ Changed ld-linux.so to only print a library name the
++ first time it is loaded when run from ldd.
++
++ Fixed a bug in ldconfig where an invalid cache could be
++ generated if a directory was specified multiple times in
++ ld.so.conf.
++
++ Changed ld-linux.so so it will return the address of a
++ weak symbol when called from dlsym in libdl (Eric
++ Youngdale.
++
++Changes in version 1.7.2:
++
++ Changed libdl.so again to fix the undefined foobar
++ problem.
++
++Changes in version 1.7.1:
++
++ Changed libdl so it will compile at optimization level
++ O3 or higher.
++
++ Changed ldconfig to always create the cache file with
++ mode 644.
++
++ Changed ldconfig to not ingore valid symlinks.
++
++ Changed ldconfig to use the library name as the soname
++ for ELF libraries that do not have an soname entry.
++
++ Changed ld-linux.so to print the actual, requested library
++ name at the time it is loaded instead of trying to figure
++ it out after the fact.
++
++Changes in version 1.7.0:
++
++ Changed ldconfig to read the actual soname from the image
++ for ELF libraries and make it available to ld-linux.so.
++ The soname for DLL libraries is still determined by
++ truncating the minor numbers from the image file name.
++
++ Changed ldconfig to no longer support the undocumented
++ sort options.
++
++ Changed ld.so to require a valid cache to find libraries
++ in directories specified in ld.so.conf. /usr/lib and /lib
++ are still searched as a last resort. Ld-linux.so already
++ operated this way.
++
++ Fixed a bug in libldso.a where the arguments to
++ shared_loader were not parsed correctly (Wolfram Gloger).
++
++ Added support for RELA-style relocations under Linux/68k
++ (Andreas Schwab).
++
++ Changed ld-linux.so to only map the cache once for all
++ libraries instead of individually for each library.
++
++ Changed ld-linux.so continue searching the cache instead of
++ giving up when failing to load the first entry found.
++
++ Changed ld-linux.so to produce output similar to ld.so when
++ run from ldd or when errors occur.
++
++Changes in version 1.6.7:
++
++ Changed the install scripts to make sure that ld.so and
++ ld-linux.so are always usable.
++
++ Added support for Linux/Sparc (Eric Youngdale).
++
++ Added support for Linux/68k (Andreas Schwab).
++
++ Fixed various bugs in ld-linux.so dealing with closing
++ files, unmapping memory, dereferencing NULL pointers and
++ printing library names (David Engel, Eric Youngdale and
++ Andreas Schwab).
++
++ Replaced the manual page for libdl with a freely
++ distributable one (Adam Richter).
++
++ Fixed a bug in ld-linux.so where LD_LIBRARY_PATH and
++ LD_PRELOAD were not cleared for setuid/setgid programs.
++
++ Fixed a bug in libdl where dlsym would not return the
++ correct address of a symbol if it was redefined in another
++ library (Oleg Kibirev).
++
++ Changed ld-linux.so to use the following order to search
++ for libraries: LD_{ELF_}LIBRARY_PATH, ld.so.cache, rpath,
++ /usr/lib and /lib.
++
++ Changed ld-linux.so to not needlessly allocate memory when
++ using ld.so.cache.
++
++Changes in version 1.6.6:
++
++ Changed ldconfig to not warn about removing stale links
++ unless the -v option is specified.
++
++ Added manual pages for libdl (from FreeBSD/Sun)
++
++ Fixed a bug in ld.so dealing with preloading of objects
++ generated by recent versions of ld (Mitch D'Souza).
++
++ Fixed bugs in ldd where some errors were either not
++ detected or not printed.
++
++ Fixed a bug in ld-linux.so where the trailing nul in a
++ library name was not being copied (Owen Taylor).
++
++Changes in version 1.6.5:
++
++ Changed ldconfig to remove stale symbolic links.
++
++ Added debug hooks in ld-linux.so and libdl.so to be used
++ by a future version of gdb (Eric Youngdale).
++
++Changes in version 1.6.4:
++
++ Change ld-linux.so to print on stdout instead of stderr
++ when run from ldd.
++
++ Added support for Debian GNU/Linux packaging.
++
++Changes in version 1.6.3:
++
++ Fixed a bug in libdl when closing a library (H.J. Lu).
++
++Changes in version 1.6.2:
++
++ Changed the error message printed by ldd when a file is
++ not a.out or ELF. It used to only list a.out formats.
++
++ Changed ldconfig to no longer cache and set up links for
++ ld-linux.so.
++
++ Changed ld-linux.so and libdl to not conflict with upcoming
++ changes in kernel header files.
++
++ Changed ld-linux.so to not print preloaded libraries.
++
++Changes in version 1.6.1:
++
++ Updated the installation script.
++
++ Changed ld.so and ld-linux.so to look for LD_AOUT_PRELOAD
++ and LD_ELF_PRELOAD, respectively, before LD_PRELOAD.
++
++ Changed ld.so and ld-linux.so to use LD_AOUT_LIBRARY_PATH
++ and LD_ELF_LIBRARY_PATH, respectively, instead of
++ AOUT_LD_LIBRARY_PATH and ELF_LD_LIBRARY_PATH.
++
++Changes in version 1.6.0:
++
++ Changed ldconfig to process libraries which do not have
++ a minor version or patch level number.
++
++ Incorporated ld-linux.so and libdl.so.
++
++ Changed ld.so and ld-linux.so to not miss entries in the
++ cache when the fully qualified library is requested.
++
++ Changed ldconfig to use stdout instead of stderr when
++ printing the cache.
++
++Changes in version 1.5.3:
++
++ LD_PRELOAD enhancements (Tristan Gigold).
++
++ LD_PRELOAD patch for linux-68k (Andreas Schwab).
++
++Changes in version 1.5.2:
++
++ More ELF changes (Mitch D'Souza).
++
++ Changed ldconfig to also update the link for ld-linux.so.
++
++Changes in version 1.5.1:
++
++ More ELF and LD_PRELOAD changes (Mitch D'Souza).
++
++Changes in version 1.5.0:
++
++ Chnaged all executables to QMAGIC (Mitch D'Souza and Rick
++ Sladkey).
++
++ Added preliminary support for ELF to ldd and ldconfig (Eric
++ Youndale and H.J. Lu).
++
++ Added support for LD_PRELOAD to ld.so (Mitch D'Souza).
++
++ Removed the "advertising" clause from the copyright notices
++ in all source files.
++
++Changes in version 1.4.4:
++
++ Changed ldconfig to support QMAGIC libraries.
++
++ Fixed a bug in ld.so where some of the error messages had
++ transposed arguments.
++
++Changes in version 1.4.3:
++
++ Fixed an obscure bug in ld.so where an index was not being
++ incremented when a library was not found using the cache.
++
++Changes in version 1.4.2:
++
++ Changed ldconfig to issue a warning and continue instead
++ of an error and exiting when a link can't be updated.
++ This is useful when some libraries are imported on read-
++ only file systems, such as an NFS mounted /usr.
++
++ Changed ld.so to be more robust in searching for libraries.
++ A library is not considered found unless it can actually be
++ loaded. If a library is not found using the cache, the
++ standard directories are searched as in pre-cache versions.
++
++Changes in version 1.4.1:
++
++ Fixed minor Makefile problems.
++
++ Added support for linux-68k.
++
++ Fixed a bug in ld.so where libraries with absolute paths
++ were not handled correctly.
++
++ Changed ld.so to ignore the directory in the names of
++ shared libraries by default. This allows older libraries
++ with absolute paths, such as the XView libraries, to take
++ advantage of the cache support.
++
++ Added a minimal usage message to ldconfig.
++
++Changes in version 1.4:
++
++ Fixed bug in ld.so where minor version numbers were not
++ reported correctly when a minor version incompatibility
++ was found.
++
++ Fixed bug in ldconfig where libraries with subversion
++ numbers greater than 9 were not compared correctly.
++
++ Added Mitch D'Souza's support for suppressing warning
++ messages from ld.so about minor version incompatibilities.
++
++ Added Mitch D'Souza's support for using a cache to speed
++ up searching for libraries in the standard directories.
++
++ Added Mitch D'Souza's support for a debugging version of
++ ld.so. Link with -lldso if you think you are experiencing
++ dynamic linker problems.
++
++Changes in version 1.3:
++
++ Added support for libraries using absolute pathnames. If I
++ had known that the XView libraries used them, I would have
++ added this earlier.
++
++ Fixed a bug handling old libraries using a pathname beginning
++ with '/' or '/lib/'.
++
++Changes in version 1.2a:
++
++ Fixed a minor bug in ldd which caused all files, specifically
++ scripts, to be recognized as binaries. Thanks to Olaf Flebbe
++ for reporting it.
++
++David Engel
++david@sw.ods.com
+diff -urN uClibc/ldso-0.9.24/include/.cvsignore uClibc.ldso.24/ldso-0.9.24/include/.cvsignore
+--- uClibc/ldso-0.9.24/include/.cvsignore 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/.cvsignore 2003-08-19 01:05:30.000000000 -0500
+@@ -0,0 +1,4 @@
++elf.h
++ld_syscalls.h
++ld_sysdep.h
++boot1_arch.h
+diff -urN uClibc/ldso-0.9.24/include/dlfcn.h uClibc.ldso.24/ldso-0.9.24/include/dlfcn.h
+--- uClibc/ldso-0.9.24/include/dlfcn.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/dlfcn.h 2003-08-19 01:05:30.000000000 -0500
+@@ -0,0 +1,22 @@
++/* User functions for run-time dynamic loading. libdl version */
++#ifndef _DLFCN_H
++#define _DLFCN_H 1
++
++#include <features.h>
++#include <bits/dlfcn.h>
++
++#define RTLD_NEXT ((void *) -1l)
++#define RTLD_DEFAULT ((void *) 0)
++
++/* Structure containing information about object searched using
++ `dladdr'. */
++typedef struct
++{
++ __const char *dli_fname; /* File name of defining object. */
++ void *dli_fbase; /* Load address of that object. */
++ __const char *dli_sname; /* Name of nearest symbol. */
++ void *dli_saddr; /* Exact value of nearest symbol. */
++} Dl_info;
++
++
++#endif /* dlfcn.h */
+diff -urN uClibc/ldso-0.9.24/include/ld_elf.h uClibc.ldso.24/ldso-0.9.24/include/ld_elf.h
+--- uClibc/ldso-0.9.24/include/ld_elf.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/ld_elf.h 2003-11-04 07:07:45.000000000 -0600
+@@ -0,0 +1,93 @@
++#ifndef LINUXELF_H
++#define LINUXELF_H
++
++#include <ld_sysdep.h> /* before elf.h to get ELF_USES_RELOCA right */
++#include <elf.h>
++#include <link.h>
++
++#ifdef DEBUG
++# define LDSO_CONF "../util/ld.so.conf"
++# define LDSO_CACHE "../util/ld.so.cache"
++# define LDSO_PRELOAD "../util/ld.so.preload"
++#else
++# define LDSO_CONF UCLIBC_RUNTIME_PREFIX "etc/ld.so.conf"
++# define LDSO_CACHE UCLIBC_RUNTIME_PREFIX "etc/ld.so.cache"
++# define LDSO_PRELOAD UCLIBC_RUNTIME_PREFIX "etc/ld.so.preload"
++#endif
++
++
++#define LIB_ANY -1
++#define LIB_DLL 0
++#define LIB_ELF 1
++#define LIB_ELF64 0x80
++#define LIB_ELF_LIBC5 2
++#define LIB_ELF_LIBC6 3
++#define LIB_ELF_LIBC0 4
++
++/* Forward declarations for stuff defined in ld_hash.h */
++struct dyn_elf;
++struct elf_resolve;
++
++
++/* Definitions and prototypes for cache stuff */
++#ifdef USE_CACHE
++extern int _dl_map_cache(void);
++extern int _dl_unmap_cache(void);
++
++#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;
++
++#else
++static inline void _dl_map_cache(void) { }
++static inline void _dl_unmap_cache(void) { }
++#endif
++
++
++/* Function prototypes for non-static stuff in readelflib1.c */
++int _dl_copy_fixups(struct dyn_elf * tpnt);
++extern int _dl_parse_copy_information(struct dyn_elf *rpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type);
++extern void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type);
++extern int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type);
++extern struct elf_resolve * _dl_load_shared_library(int secure,
++ struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname);
++extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
++ struct dyn_elf **rpnt, char *libname);
++extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname);
++extern int _dl_linux_resolve(void);
++
++
++/*
++ * Datatype of a relocation on this platform
++ */
++#ifdef ELF_USES_RELOCA
++# define ELF_RELOC ElfW(Rela)
++#else
++# define ELF_RELOC ElfW(Rel)
++#endif
++
++
++/* Convert between the Linux flags for page protections and the
++ ones specified in the ELF standard. */
++#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
++ (((X) & PF_W) ? PROT_WRITE : 0) | \
++ (((X) & PF_X) ? PROT_EXEC : 0))
++
++
++#endif /* LINUXELF_H */
+diff -urN uClibc/ldso-0.9.24/include/ld_hash.h uClibc.ldso.24/ldso-0.9.24/include/ld_hash.h
+--- uClibc/ldso-0.9.24/include/ld_hash.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/ld_hash.h 2003-08-19 08:11:05.000000000 -0500
+@@ -0,0 +1,103 @@
++#ifndef _LD_HASH_H_
++#define _LD_HASH_H_
++
++#ifndef RTLD_NEXT
++#define RTLD_NEXT ((void*)-1)
++#endif
++
++struct dyn_elf{
++ unsigned long flags;
++ struct elf_resolve * dyn;
++ struct dyn_elf * next_handle; /* Used by dlopen et al. */
++ struct dyn_elf * next;
++ struct dyn_elf * prev;
++};
++
++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. */
++ ElfW(Addr) loadaddr; /* Base address shared object is loaded at. */
++ char *libname; /* Absolute file name object was found in. */
++ ElfW(Dyn) *dynamic_addr; /* Dynamic section of the shared object. */
++ struct elf_resolve * next;
++ struct elf_resolve * prev;
++ /* Nothing after this address is used by gdb. */
++ enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
++ struct dyn_elf * symbol_scope;
++ unsigned short usage_count;
++ unsigned short int init_flag;
++ unsigned int nbucket;
++ unsigned long * elf_buckets;
++ /*
++ * These are only used with ELF style shared libraries
++ */
++ unsigned long nchain;
++ unsigned long * chains;
++ unsigned long dynamic_info[24];
++
++ unsigned long dynamic_size;
++ unsigned long n_phent;
++ Elf32_Phdr * ppnt;
++
++#if defined(__mips__)
++ /* Needed for MIPS relocation */
++ unsigned long mips_gotsym;
++ unsigned long mips_local_gotno;
++ unsigned long mips_symtabno;
++#endif
++
++#ifdef __powerpc__
++ /* this is used to store the address of relocation data words, so
++ * we don't have to calculate it every time, which requires a divide */
++ unsigned long data_words;
++#endif
++};
++
++#define COPY_RELOCS_DONE 1
++#define RELOCS_DONE 2
++#define JMP_RELOCS_DONE 4
++#define INIT_FUNCS_CALLED 8
++
++extern struct dyn_elf * _dl_symbol_tables;
++extern struct elf_resolve * _dl_loaded_modules;
++extern struct dyn_elf * _dl_handles;
++
++extern struct elf_resolve * _dl_check_hashed_files(const char * libname);
++extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
++ char * loadaddr, unsigned long * dynamic_info,
++ unsigned long dynamic_addr, unsigned long dynamic_size);
++
++enum caller_type{symbolrel=0,copyrel=1,resolver=2};
++extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1,
++ struct elf_resolve * f_tpnt, enum caller_type);
++
++extern int _dl_linux_dynamic_link(void);
++
++extern char * _dl_library_path;
++extern char * _dl_not_lazy;
++extern unsigned long _dl_elf_hash(const char * name);
++
++static inline int _dl_symbol(char * name)
++{
++ if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
++ return 0;
++ return 1;
++}
++
++
++#define LD_ERROR_NOFILE 1
++#define LD_ERROR_NOZERO 2
++#define LD_ERROR_NOTELF 3
++#define LD_ERROR_NOTMAGIC 4
++#define LD_ERROR_NOTDYN 5
++#define LD_ERROR_MMAP_FAILED 6
++#define LD_ERROR_NODYNAMIC 7
++#define LD_WRONG_RELOCS 8
++#define LD_BAD_HANDLE 9
++#define LD_NO_SYMBOL 10
++
++
++
++#endif /* _LD_HASH_H_ */
++
++
+diff -urN uClibc/ldso-0.9.24/include/ld_string.h uClibc.ldso.24/ldso-0.9.24/include/ld_string.h
+--- uClibc/ldso-0.9.24/include/ld_string.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/ld_string.h 2003-09-29 16:46:00.000000000 -0500
+@@ -0,0 +1,281 @@
++#ifndef _LINUX_STRING_H_
++#define _LINUX_STRING_H_
++
++extern void *_dl_malloc(int size);
++extern char *_dl_getenv(const char *symbol, char **envp);
++extern void _dl_unsetenv(const char *symbol, char **envp);
++extern char *_dl_strdup(const char *string);
++extern void _dl_dprintf(int, const char *, ...);
++
++
++static size_t _dl_strlen(const char * str);
++static char *_dl_strcat(char *dst, const char *src);
++static char * _dl_strcpy(char * dst,const char *src);
++static int _dl_strcmp(const char * s1,const char * s2);
++static int _dl_strncmp(const char * s1,const char * s2,size_t len);
++static char * _dl_strchr(const char * str,int c);
++static char *_dl_strrchr(const char *str, int c);
++static char *_dl_strstr(const char *s1, const char *s2);
++static void * _dl_memcpy(void * dst, const void * src, size_t len);
++static int _dl_memcmp(const void * s1,const void * s2,size_t len);
++static void *_dl_memset(void * str,int c,size_t len);
++static char *_dl_get_last_path_component(char *path);
++static char *_dl_simple_ltoa(char * local, unsigned long i);
++static char *_dl_simple_ltoahex(char * local, unsigned long i);
++
++#ifndef NULL
++#define NULL ((void *) 0)
++#endif
++
++static inline size_t _dl_strlen(const char * str)
++{
++ register char *ptr = (char *) str;
++
++ while (*ptr)
++ ptr++;
++ return (ptr - str);
++}
++
++static inline char *_dl_strcat(char *dst, const char *src)
++{
++ register char *ptr = dst;
++
++ while (*ptr)
++ ptr++;
++
++ while (*src)
++ *ptr++ = *src++;
++ *ptr = '\0';
++
++ return dst;
++}
++
++static inline char * _dl_strcpy(char * dst,const char *src)
++{
++ register char *ptr = dst;
++
++ while (*src)
++ *dst++ = *src++;
++ *dst = '\0';
++
++ return ptr;
++}
++
++static inline int _dl_strcmp(const char * s1,const char * s2)
++{
++ register unsigned char c1, c2;
++
++ do {
++ c1 = (unsigned char) *s1++;
++ c2 = (unsigned char) *s2++;
++ if (c1 == '\0')
++ return c1 - c2;
++ }
++ while (c1 == c2);
++
++ return c1 - c2;
++}
++
++static inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
++{
++ register unsigned char c1 = '\0';
++ register unsigned char c2 = '\0';
++
++ while (len > 0) {
++ c1 = (unsigned char) *s1++;
++ c2 = (unsigned char) *s2++;
++ if (c1 == '\0' || c1 != c2)
++ return c1 - c2;
++ len--;
++ }
++
++ return c1 - c2;
++}
++
++static inline char * _dl_strchr(const char * str,int c)
++{
++ register char ch;
++
++ do {
++ if ((ch = *str) == c)
++ return (char *) str;
++ str++;
++ }
++ while (ch);
++
++ return 0;
++}
++
++static inline char *_dl_strrchr(const char *str, int c)
++{
++ register char *prev = 0;
++ register char *ptr = (char *) str;
++
++ while (*ptr != '\0') {
++ if (*ptr == c)
++ prev = ptr;
++ ptr++;
++ }
++ if (c == '\0')
++ return(ptr);
++ return(prev);
++}
++
++
++static inline char *_dl_strstr(const char *s1, const char *s2)
++{
++ register const char *s = s1;
++ register const char *p = s2;
++
++ do {
++ if (!*p) {
++ return (char *) s1;;
++ }
++ if (*p == *s) {
++ ++p;
++ ++s;
++ } else {
++ p = s2;
++ if (!*s) {
++ return NULL;
++ }
++ s = ++s1;
++ }
++ } while (1);
++}
++
++static inline void * _dl_memcpy(void * dst, const void * src, size_t len)
++{
++ register char *a = dst;
++ register const char *b = src;
++
++ while (len--)
++ *a++ = *b++;
++
++ return dst;
++}
++
++
++static inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
++{
++ unsigned char *c1 = (unsigned char *)s1;
++ unsigned char *c2 = (unsigned char *)s2;
++
++ while (len--) {
++ if (*c1 != *c2)
++ return *c1 - *c2;
++ c1++;
++ c2++;
++ }
++ return 0;
++}
++
++static inline void * _dl_memset(void * str,int c,size_t len)
++{
++ register char *a = str;
++
++ while (len--)
++ *a++ = c;
++
++ return str;
++}
++
++static inline char *_dl_get_last_path_component(char *path)
++{
++ char *s;
++ register char *ptr = path;
++ register char *prev = 0;
++
++ while (*ptr)
++ ptr++;
++ s = ptr - 1;
++
++ /* strip trailing slashes */
++ while (s != path && *s == '/') {
++ *s-- = '\0';
++ }
++
++ /* find last component */
++ ptr = path;
++ while (*ptr != '\0') {
++ if (*ptr == '/')
++ prev = ptr;
++ ptr++;
++ }
++ s = prev;
++
++ if (s == NULL || s[1] == '\0')
++ return path;
++ else
++ return s+1;
++}
++
++/* Early on, we can't call printf, so use this to print out
++ * numbers using the SEND_STDERR() macro */
++static inline char *_dl_simple_ltoa(char * local, unsigned long i)
++{
++ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
++ char *p = &local[22];
++ *p-- = '\0';
++ do {
++ *p-- = '0' + i % 10;
++ i /= 10;
++ } while (i > 0);
++ return p + 1;
++}
++
++static inline char *_dl_simple_ltoahex(char * local, unsigned long i)
++{
++ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
++ char *p = &local[22];
++ *p-- = '\0';
++ do {
++ char temp = i % 0x10;
++ if (temp <= 0x09)
++ *p-- = '0' + temp;
++ else
++ *p-- = 'a' - 0x0a + temp;
++ i /= 0x10;
++ } while (i > 0);
++ *p-- = 'x';
++ *p-- = '0';
++ return p + 1;
++}
++
++
++#if defined(mc68000) || defined(__arm__) || defined(__mips__) || defined(__sh__) || defined(__powerpc__)
++/* On some arches 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
++
++#define SEND_ADDRESS_STDERR(X, add_a_newline) { \
++ char tmp[22], *tmp1; \
++ _dl_memset(tmp, 0, sizeof(tmp)); \
++ tmp1=_dl_simple_ltoahex( tmp, (unsigned long)(X)); \
++ _dl_write(2, tmp1, _dl_strlen(tmp1)); \
++ if (add_a_newline) { \
++ tmp[0]='\n'; \
++ _dl_write(2, tmp, 1); \
++ } \
++};
++
++#define SEND_NUMBER_STDERR(X, add_a_newline) { \
++ char tmp[22], *tmp1; \
++ _dl_memset(tmp, 0, sizeof(tmp)); \
++ tmp1=_dl_simple_ltoa( tmp, (unsigned long)(X)); \
++ _dl_write(2, tmp1, _dl_strlen(tmp1)); \
++ if (add_a_newline) { \
++ tmp[0]='\n'; \
++ _dl_write(2, tmp, 1); \
++ } \
++};
++
++
++#endif
+diff -urN uClibc/ldso-0.9.24/include/ld_syscall.h uClibc.ldso.24/ldso-0.9.24/include/ld_syscall.h
+--- uClibc/ldso-0.9.24/include/ld_syscall.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/ld_syscall.h 2003-08-19 01:05:30.000000000 -0500
+@@ -0,0 +1,157 @@
++#ifndef _LD_SYSCALL_H_
++#define _LD_SYSCALL_H_
++
++/* Pull in the arch specific syscall implementation */
++#include <ld_syscalls.h>
++/* For MAP_ANONYMOUS -- differs between platforms */
++#include <asm/mman.h>
++/* Pull in whatever this particular arch's kernel thinks the kernel version of
++ * struct stat should look like. It turns out that each arch has a different
++ * opinion on the subject, and different kernel revs use different names... */
++#define kernel_stat stat
++#include <bits/kernel_stat.h>
++
++
++/* Encoding of the file mode. */
++#define S_IFMT 0170000 /* These bits determine file type. */
++
++/* File types. */
++#define S_IFDIR 0040000 /* Directory. */
++#define S_IFCHR 0020000 /* Character device. */
++#define S_IFBLK 0060000 /* Block device. */
++#define S_IFREG 0100000 /* Regular file. */
++#define S_IFIFO 0010000 /* FIFO. */
++#define S_IFLNK 0120000 /* Symbolic link. */
++#define S_IFSOCK 0140000 /* Socket. */
++
++/* Protection bits. */
++
++#define S_ISUID 04000 /* Set user ID on execution. */
++#define S_ISGID 02000 /* Set group ID on execution. */
++#define S_ISVTX 01000 /* Save swapped text after use (sticky). */
++#define S_IREAD 0400 /* Read by owner. */
++#define S_IWRITE 0200 /* Write by owner. */
++#define S_IEXEC 0100 /* Execute by owner. */
++
++
++/* Here are the definitions for some syscalls that are used
++ by the dynamic linker. The idea is that we want to be able
++ to call these before the errno symbol is dynamicly linked, so
++ we use our own version here. Note that we cannot assume any
++ dynamic linking at all, so we cannot return any error codes.
++ We just punt if there is an error. */
++
++
++#define __NR__dl_exit __NR_exit
++static inline _syscall1(void, _dl_exit, int, status);
++
++
++#define __NR__dl_close __NR_close
++static inline _syscall1(int, _dl_close, int, fd);
++
++
++#if defined(__powerpc__) || defined(__mips__) || defined(__sh__)
++/* PowerPC, MIPS and SuperH have a different calling convention for mmap(). */
++#define __NR__dl_mmap __NR_mmap
++static inline _syscall6(void *, _dl_mmap, void *, start, size_t, length,
++ int, prot, int, flags, int, fd, off_t, offset);
++#else
++#define __NR__dl_mmap_real __NR_mmap
++static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
++
++static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
++ int flags, int fd, unsigned long offset)
++{
++ unsigned long buffer[6];
++
++ buffer[0] = (unsigned long) addr;
++ buffer[1] = (unsigned long) size;
++ buffer[2] = (unsigned long) prot;
++ buffer[3] = (unsigned long) flags;
++ buffer[4] = (unsigned long) fd;
++ buffer[5] = (unsigned long) offset;
++ return (void *) _dl_mmap_real(buffer);
++}
++#endif
++
++#ifndef _dl_MAX_ERRNO
++#define _dl_MAX_ERRNO 4096
++#endif
++#define _dl_mmap_check_error(__res) \
++ (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
++#ifndef MAP_ANONYMOUS
++#ifdef __sparc__
++#define MAP_ANONYMOUS 0x20
++#else
++#error MAP_ANONYMOUS not defined and suplementary value not known
++#endif
++#endif
++
++
++#define __NR__dl_open __NR_open
++#define O_RDONLY 0x0000
++#define O_WRONLY 01
++#define O_RDWR 02
++#define O_CREAT 0100 /* not fcntl */
++static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
++
++#define __NR__dl_write __NR_write
++static inline _syscall3(unsigned long, _dl_write, int, fd,
++ const void *, buf, unsigned long, count);
++
++
++#define __NR__dl_read __NR_read
++static inline _syscall3(unsigned long, _dl_read, int, fd,
++ const void *, buf, unsigned long, count);
++
++#define __NR__dl_mprotect __NR_mprotect
++static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
++
++
++
++#define __NR__dl_stat __NR_stat
++static inline _syscall2(int, _dl_stat, const char *, file_name, struct stat *, buf);
++
++
++#define __NR__dl_munmap __NR_munmap
++static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
++
++#define __NR__dl_getuid __NR_getuid
++static inline _syscall0(uid_t, _dl_getuid);
++
++#define __NR__dl_geteuid __NR_geteuid
++static inline _syscall0(uid_t, _dl_geteuid);
++
++#define __NR__dl_getgid __NR_getgid
++static inline _syscall0(gid_t, _dl_getgid);
++
++#define __NR__dl_getegid __NR_getegid
++static inline _syscall0(gid_t, _dl_getegid);
++
++#define __NR__dl_getpid __NR_getpid
++static inline _syscall0(gid_t, _dl_getpid);
++
++/*
++ * Not an actual syscall, but we need something in assembly to say whether
++ * this is OK or not.
++ */
++static inline int _dl_suid_ok(void)
++{
++ uid_t uid, euid, gid, egid;
++
++ uid = _dl_getuid();
++ euid = _dl_geteuid();
++ gid = _dl_getgid();
++ egid = _dl_getegid();
++
++ if(uid == euid && gid == egid)
++ return 1;
++ else
++ return 0;
++}
++
++#define __NR__dl_readlink __NR_readlink
++static inline _syscall3(int, _dl_readlink, const char *, path, char *, buf, size_t, bufsiz);
++
++#endif /* _LD_SYSCALL_H_ */
++
+diff -urN uClibc/ldso-0.9.24/include/ldso.h uClibc.ldso.24/ldso-0.9.24/include/ldso.h
+--- uClibc/ldso-0.9.24/include/ldso.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/include/ldso.h 2003-08-19 01:05:30.000000000 -0500
+@@ -0,0 +1,11 @@
++#include <features.h>
++/* Pull in compiler and arch stuff */
++#include <stdlib.h>
++#include <stdarg.h>
++/* Pull in the arch specific type information */
++#include <sys/types.h>
++/* Now the ldso specific headers */
++#include <ld_elf.h>
++#include <ld_syscall.h>
++#include <ld_hash.h>
++#include <ld_string.h>
+diff -urN uClibc/ldso-0.9.24/ldso/.cvsignore uClibc.ldso.24/ldso-0.9.24/ldso/.cvsignore
+--- uClibc/ldso-0.9.24/ldso/.cvsignore 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/.cvsignore 2003-08-19 01:05:31.000000000 -0500
+@@ -0,0 +1,2 @@
++ld-uclibc.so*
++_dl_progname.h
+diff -urN uClibc/ldso-0.9.24/ldso/Makefile uClibc.ldso.24/ldso-0.9.24/ldso/Makefile
+--- uClibc/ldso-0.9.24/ldso/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/Makefile 2004-03-01 02:58:58.000000000 -0600
+@@ -0,0 +1,101 @@
++# Makefile for uClibc
++#
++# Copyright (C) 2000 by Lineo, inc.
++# Copyright (C) 2000-2002 Erik Andersen <andersen@uclibc.org>
++#
++# This program 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.
++#
++# 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 Library General Public License for more
++# details.
++#
++# You should have received a copy of the GNU Library General Public License
++# along with this program; if not, write to the Free Software Foundation, Inc.,
++# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++#
++# Derived in part from the Linux-8086 C library, the GNU C Library, and several
++# other sundry sources. Files within this library are copyright by their
++# respective copyright holders.
++
++
++TOPDIR=../../
++include $(TOPDIR)Rules.mak
++LDSO_FULLNAME=ld-uClibc-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
++
++
++XXFLAGS=$(XWARNINGS) $(OPTIMIZATION) $(XARCH_CFLAGS) $(CPU_CFLAGS) $(PICFLAG) \
++ -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
++ -fno-builtin -nostdinc -I$(TOPDIR)ldso-0.9.24/include -I. -I$(TOPDIR)include
++
++ifeq ($(SUPPORT_LD_DEBUG),y)
++XXFLAGS=$(XWARNINGS) $(XARCH_CFLAGS) $(CPU_CFLAGS) $(PICFLAG) \
++ -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
++ -fno-builtin -nostdinc -I$(TOPDIR)ldso-0.9.24/include -I. -I$(TOPDIR)include
++# Not really much point in including debugging info, since gdb
++# can't really debug ldso, since gdb requires help from ldso to
++# debug things....
++XXFLAGS+=-Os #-g3
++endif
++
++# BEWARE!!! At least mips* will die if -O0 is used!!!
++XXFLAGS :=$(XXFLAGS:-O0=-O1)
++
++XXFLAGS+=$(shell $(CC) -print-search-dirs | sed -ne "s/install: *\(.*\)/-I\1include/gp")
++LDFLAGS=$(CPU_LDFLAGS-y) -shared --warn-common --export-dynamic --sort-common \
++ -z combreloc --discard-locals --discard-all --no-undefined
++
++CSRC= ldso.c #hash.c readelflib1.c $(TARGET_ARCH)/elfinterp.c
++COBJS=$(patsubst %.c,%.o, $(CSRC))
++ASRC=$(shell ls $(TARGET_ARCH)/*.S)
++AOBJS=$(patsubst %.S,%.o, $(ASRC))
++OBJS=$(AOBJS) $(COBJS)
++
++ifneq ($(strip $(SUPPORT_LD_DEBUG)),y)
++LDFLAGS+=-s
++endif
++
++ifeq ($(strip $(SUPPORT_LD_DEBUG)),y)
++XXFLAGS+=-D__SUPPORT_LD_DEBUG__
++endif
++
++ifeq ($(strip $(SUPPORT_LD_DEBUG_EARLY)),y)
++XXFLAGS+=-D__SUPPORT_LD_DEBUG_EARLY__
++endif
++
++ifeq ($(strip $(FORCE_SHAREABLE_TEXT_SEGMENTS)),y)
++XXFLAGS+=-DFORCE_SHAREABLE_TEXT_SEGMENTS
++endif
++
++#This stuff will not work with -fomit-frame-pointer
++XXFLAGS := $(XXFLAGS:-fomit-frame-pointer=)
++
++all: lib
++
++lib:: _dl_progname.h $(OBJS) $(DLINK_OBJS)
++ $(LD) $(LDFLAGS) -e _dl_boot -soname=$(UCLIBC_LDSO) \
++ -o $(LDSO_FULLNAME) $(OBJS) $(LIBGCC);
++ $(INSTALL) -d $(TOPDIR)lib
++ $(INSTALL) -m 755 $(LDSO_FULLNAME) $(TOPDIR)lib
++ $(LN) -sf $(LDSO_FULLNAME) $(TOPDIR)lib/$(UCLIBC_LDSO)
++
++_dl_progname.h: Makefile
++ echo "const char *_dl_progname=\""$(UCLIBC_LDSO)"\";" > _dl_progname.h
++ echo "#include \"$(TARGET_ARCH)/elfinterp.c\"" >> _dl_progname.h
++
++
++$(COBJS): %.o : %.c
++ $(CC) $(XXFLAGS) -I../libdl -c $< -o $@
++ $(STRIPTOOL) -x -R .note -R .comment $*.o
++
++$(AOBJS): %.o : %.S
++ $(CC) $(XXFLAGS) -I../libdl -c $< -o $@
++ $(STRIPTOOL) -x -R .note -R .comment $*.o
++
++ldso.o: ldso.c hash.c readelflib1.c $(TARGET_ARCH)/elfinterp.c _dl_progname.h
++
++clean:
++ $(RM) $(UCLIBC_LDSO)* $(OBJS) $(LDSO_FULLNAME)* core *.o *.a *.s *.i _dl_progname.h ldso.h *~
+diff -urN uClibc/ldso-0.9.24/ldso/arm/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/arm/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/arm/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/arm/boot1_arch.h 2002-11-13 18:53:49.000000000 -0600
+@@ -0,0 +1,30 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. */
++
++/* Overrive the default _dl_boot function, and replace it with a bit of asm.
++ * Then call the real _dl_boot function, which is now named _dl_boot2. */
++
++asm("" \
++" .text\n" \
++" .globl _dl_boot\n" \
++"_dl_boot:\n" \
++" mov r7, sp\n" \
++" @ldr r0, [sp], #4\n" \
++" mov r0, sp\n" \
++" bl _dl_boot2\n" \
++" mov r6, r0\n" \
++" mov r0, r7\n" \
++" mov pc, r6\n" \
++);
++
++#define _dl_boot _dl_boot2
++#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X)
++
++
++ /* It seems ARM needs an offset here */
++#undef ELFMAGIC
++#define ELFMAGIC ELFMAG+load_addr
++
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/arm/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/arm/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/arm/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/arm/elfinterp.c 2002-11-07 21:20:59.000000000 -0600
+@@ -0,0 +1,462 @@
++/* vi: set sw=4 ts=4: */
++/* ARM ELF shared library loader suppport
++ *
++ * Copyright (C) 2001-2002, Erik Andersen
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] =
++{
++ [0] "R_ARM_NONE", "R_ARM_PC24", "R_ARM_ABS32", "R_ARM_REL32",
++ [4] "R_ARM_PC13", "R_ARM_ABS16", "R_ARM_ABS12", "R_ARM_THM_ABS5",
++ [8] "R_ARM_ABS8", "R_ARM_SBREL32","R_ARM_THM_PC22", "R_ARM_THM_PC8",
++ [12] "R_ARM_AMP_VCALL9", "R_ARM_SWI24", "R_ARM_THM_SWI8", "R_ARM_XPC25",
++ [16] "R_ARM_THM_XPC22",
++ [20] "R_ARM_COPY", "R_ARM_GLOB_DAT","R_ARM_JUMP_SLOT", "R_ARM_RELATIVE",
++ [24] "R_ARM_GOTOFF", "R_ARM_GOTPC", "R_ARM_GOT32", "R_ARM_PLT32",
++ [32] "R_ARM_ALU_PCREL_7_0","R_ARM_ALU_PCREL_15_8","R_ARM_ALU_PCREL_23_15","R_ARM_LDR_SBREL_11_0",
++ [36] "R_ARM_ALU_SBREL_19_12","R_ARM_ALU_SBREL_27_20",
++ [100] "R_ARM_GNU_VTENTRY","R_ARM_GNU_VTINHERIT","R_ARM_THM_PC11","R_ARM_THM_PC9",
++ [249] "R_ARM_RXPC25", "R_ARM_RSBREL32", "R_ARM_THM_RPC22", "R_ARM_RREL32",
++ [253] "R_ARM_RABS22", "R_ARM_RPC24", "R_ARM_RBASE",
++};
++
++static const char *
++_dl_reltypes(int type)
++{
++ static char buf[22];
++ const char *str;
++
++ if (type >= (sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ {
++ str =_dl_simple_ltoa( buf, (unsigned long)(type));
++ }
++ return str;
++}
++
++static
++void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
++{
++ if(_dl_debug_symbols)
++ {
++ if(symtab_index){
++ _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
++{
++ if(_dl_debug_reloc)
++ {
++ int symtab_index;
++ const char *sym;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend,
++ sym);
++#else
++ _dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ sym);
++#endif
++ }
++}
++#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. */
++
++extern int _dl_linux_resolve(void);
++
++unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ ELF_RELOC *this_reloc;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rel_addr;
++ int symtab_index;
++ char *new_addr;
++ char **got_addr;
++ unsigned long instr_addr;
++
++ rel_addr = (ELF_RELOC *) (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 = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++
++ if (reloc_type != R_ARM_JUMP_SLOT) {
++ _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
++ _dl_progname);
++ _dl_exit(1);
++ };
++
++ /* Address of jump instruction to fix up */
++ instr_addr = ((unsigned long) this_reloc->r_offset +
++ (unsigned long) tpnt->loadaddr);
++ got_addr = (char **) instr_addr;
++
++ /* Get the address of the GOT entry */
++ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
++ tpnt->symbol_scope, tpnt, resolver);
++ if (!new_addr) {
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ _dl_exit(1);
++ };
++#if defined (__SUPPORT_LD_DEBUG__)
++ if ((unsigned long) got_addr < 0x40000000)
++ {
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
++ strtab + symtab[symtab_index].st_name);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
++ }
++ }
++ if (!_dl_debug_nofixups) {
++ *got_addr = new_addr;
++ }
++#else
++ *got_addr = new_addr;
++#endif
++
++ return (unsigned long) new_addr;
++}
++
++static int
++_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
++ unsigned long rel_addr, unsigned long rel_size,
++ int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
++{
++ int i;
++ char *strtab;
++ int goof = 0;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rpnt;
++ int symtab_index;
++ /* Now parse the relocation information */
++
++ rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof(ELF_RELOC);
++
++ symtab = (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++) {
++ int res;
++
++ 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;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,rpnt);
++#endif
++
++ res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
++
++ if (res==0) continue;
++
++ _dl_dprintf(2, "\n%s: ",_dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++ if (res <0)
++ {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
++#endif
++ _dl_exit(-res);
++ }
++ else if (res >0)
++ {
++ _dl_dprintf(2, "can't resolve symbol\n");
++ goof += res;
++ }
++ }
++ return goof;
++}
++
++static unsigned long
++fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
++{
++ static void *fix_page;
++ static unsigned int fix_offset;
++ unsigned int *fix_address;
++ if (! fix_page)
++ {
++ fix_page = _dl_mmap (NULL, 4096 , PROT_READ | PROT_WRITE | PROT_EXEC,
++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++ fix_offset = 0;
++ }
++
++ fix_address = (unsigned int *)(fix_page + fix_offset);
++ fix_address[0] = 0xe51ff004; /* ldr pc, [pc, #-4] */
++ fix_address[1] = value;
++
++ fix_offset += 8;
++ if (fix_offset >= 4096)
++ fix_page = NULL;
++
++ return (unsigned long)fix_address;
++}
++
++static int
++_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int goof = 0;
++
++ reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) 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) {
++
++ symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
++ scope, (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), symbolrel);
++
++ /*
++ * 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) {
++ goof++;
++ }
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ {
++ unsigned long old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_ARM_NONE:
++ break;
++ case R_ARM_ABS32:
++ *reloc_addr += symbol_addr;
++ break;
++ case R_ARM_PC24:
++ {
++ unsigned long addend;
++ long newvalue, topbits;
++
++ addend = *reloc_addr & 0x00ffffff;
++ if (addend & 0x00800000) addend |= 0xff000000;
++
++ newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
++ topbits = newvalue & 0xfe000000;
++ if (topbits != 0xfe000000 && topbits != 0x00000000)
++ {
++ newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
++ - (unsigned long)reloc_addr + (addend << 2);
++ topbits = newvalue & 0xfe000000;
++ if (topbits != 0xfe000000 && topbits != 0x00000000)
++ {
++ _dl_dprintf(2,"symbol '%s': R_ARM_PC24 relocation out of range.",
++ symtab[symtab_index].st_name);
++ _dl_exit(1);
++ }
++ }
++ newvalue >>= 2;
++ symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
++ *reloc_addr = symbol_addr;
++ break;
++ }
++ case R_ARM_GLOB_DAT:
++ case R_ARM_JUMP_SLOT:
++ *reloc_addr = symbol_addr;
++ break;
++ case R_ARM_RELATIVE:
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ break;
++ case R_ARM_COPY:
++#if 0
++ /* Do this later */
++ _dl_dprintf(2, "Doing copy for symbol ");
++ if (symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
++ _dl_dprintf(2, "\n");
++ _dl_memcpy((void *) symtab[symtab_index].st_value,
++ (void *) symbol_addr, symtab[symtab_index].st_size);
++#endif
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++ }
++
++#endif
++
++ return goof;
++}
++
++static int
++_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ unsigned long *reloc_addr;
++
++ reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ {
++ unsigned long old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_ARM_NONE:
++ break;
++ case R_ARM_JUMP_SLOT:
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++ }
++
++#endif
++ return 0;
++
++}
++
++/* 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 */
++static int
++_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int goof = 0;
++
++ reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ if (reloc_type != R_ARM_COPY)
++ return 0;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++
++ if (symtab_index) {
++
++ symbol_addr = (unsigned long) _dl_find_hash(strtab +
++ symtab[symtab_index].st_name, scope,
++ NULL, copyrel);
++ if (!symbol_addr) goof++;
++ }
++ if (!goof) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_move)
++ _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_size,
++ symbol_addr, symtab[symtab_index].st_value);
++#endif
++ _dl_memcpy((char *) symtab[symtab_index].st_value,
++ (char *) symbol_addr, symtab[symtab_index].st_size);
++ }
++
++ return goof;
++}
++
++void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
++}
++
++int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
++}
++
++int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
++}
++
+diff -urN uClibc/ldso-0.9.24/ldso/arm/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/arm/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/arm/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/arm/ld_syscalls.h 2003-09-09 01:11:11.000000000 -0500
+@@ -0,0 +1,19 @@
++/* Define the __set_errno macro as nothing so that INLINE_SYSCALL
++ * won't set errno, which is important since we make system calls
++ * before the errno symbol is dynamicly linked. */
++
++#define __set_errno(X) {(void)(X);}
++
++/* Prepare for the case that `__builtin_expect' is not available. */
++#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
++#define __builtin_expect(x, expected_value) (x)
++#endif
++#ifndef likely
++# define likely(x) __builtin_expect((!!(x)),1)
++#endif
++#ifndef unlikely
++# define unlikely(x) __builtin_expect((!!(x)),0)
++#endif
++
++#include "sys/syscall.h"
++
+diff -urN uClibc/ldso-0.9.24/ldso/arm/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/arm/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/arm/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/arm/ld_sysdep.h 2002-08-09 09:41:04.000000000 -0500
+@@ -0,0 +1,124 @@
++/*
++ * 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 long*) ARGS)
++
++/*
++ * Initialization sequence for a GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
++ GOT_BASE[1] = (unsigned long) 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_ARM_ABS32: \
++ *REL += SYMBOL; \
++ break; \
++ case R_ARM_PC24: \
++ { long newvalue, topbits; \
++ unsigned long addend = *REL & 0x00ffffff; \
++ if (addend & 0x00800000) addend |= 0xff000000; \
++ newvalue=SYMBOL-(unsigned long)REL+(addend<<2); \
++ topbits = newvalue & 0xfe000000; \
++ if (topbits!=0xfe000000&&topbits!=0x00000000){ \
++ newvalue = fix_bad_pc24(REL, SYMBOL) \
++ -(unsigned long)REL+(addend<<2); \
++ topbits = newvalue & 0xfe000000; \
++ if (topbits!=0xfe000000&&topbits!=0x00000000){ \
++ SEND_STDERR("R_ARM_PC24 relocation out of range\n");\
++ _dl_exit(1); } } \
++ newvalue>>=2; \
++ SYMBOL=(*REL&0xff000000)|(newvalue & 0x00ffffff); \
++ *REL=SYMBOL; \
++ } \
++ break; \
++ case R_ARM_GLOB_DAT: \
++ case R_ARM_JUMP_SLOT: \
++ *REL = SYMBOL; \
++ break; \
++ case R_ARM_RELATIVE: \
++ *REL += (unsigned long) LOAD; \
++ break; \
++ case R_ARM_NONE: \
++ break; \
++ default: \
++ SEND_STDERR("Aiieeee!"); \
++ _dl_exit(1); \
++ }
++
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. This routine has to exit the current function, then
++ * call the _dl_elf_main function.
++ */
++
++#define START() return _dl_elf_main;
++
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_ARM
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "ARM"
++
++struct elf_resolve;
++unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
++
++static inline unsigned long arm_modulus(unsigned long m, unsigned long p) {
++ unsigned long i,t,inc;
++ i=p; t=0;
++ while(!(i&(1<<31))) {
++ i<<=1;
++ t++;
++ }
++ t--;
++ for(inc=t;inc>2;inc--) {
++ i=p<<inc;
++ if(i&(1<<31))
++ break;
++ while(m>=i) {
++ m-=i;
++ i<<=1;
++ if(i&(1<<31))
++ break;
++ if(i<p)
++ break;
++ }
++ }
++ while(m>=p) {
++ m-=p;
++ }
++ return m;
++}
++
++#define do_rem(result, n, base) result=arm_modulus(n,base);
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/arm/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/arm/resolve.S
+--- uClibc/ldso-0.9.24/ldso/arm/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/arm/resolve.S 2002-08-12 04:03:30.000000000 -0500
+@@ -0,0 +1,43 @@
++/*
++ * This function is _not_ called directly. It is jumped to (so no return
++ * address is on the stack) when attempting to use a symbol that has not yet
++ * been resolved. The first time a jump symbol (such as a function call inside
++ * a shared library) is used (before it gets resolved) it will jump here to
++ * _dl_linux_resolve. When we get called the stack looks like this:
++ * reloc_entry
++ * tpnt
++ *
++ * This function saves all the registers, puts a copy of reloc_entry and tpnt
++ * on the stack (as function arguments) then make the function call
++ * _dl_linux_resolver(tpnt, reloc_entry). _dl_linux_resolver() figures out
++ * where the jump symbol is _really_ supposed to have jumped to and returns
++ * that to us. Once we have that, we overwrite tpnt with this fixed up
++ * address. We then clean up after ourselves, put all the registers back how we
++ * found them, then we jump to the fixed up address, which is where the jump
++ * symbol that got us here really wanted to jump to in the first place.
++ * -Erik Andersen
++ */
++
++#define sl r10
++#define fp r11
++#define ip r12
++
++.text
++.globl _dl_linux_resolve
++.type _dl_linux_resolve,%function
++.align 4;
++
++_dl_linux_resolve:
++ stmdb sp!, {r0, r1, r2, r3, sl, fp}
++ sub r1, ip, lr
++ sub r1, r1, #4
++ add r1, r1, r1
++ ldr r0, [lr, #-4]
++ mov r3,r0
++
++ bl _dl_linux_resolver
++
++ mov ip, r0
++ ldmia sp!, {r0, r1, r2, r3, sl, fp, lr}
++ mov pc,ip
++.size _dl_linux_resolve, .-_dl_linux_resolve
+diff -urN uClibc/ldso-0.9.24/ldso/cris/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/cris/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/cris/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/cris/boot1_arch.h 2003-09-19 07:11:43.000000000 -0500
+@@ -0,0 +1,17 @@
++/*
++ * This code fix the stack pointer so that the dynamic linker
++ * can find argc, argv and auxvt (Auxillary Vector Table).
++ */
++asm("" \
++" .text\n" \
++" .globl _dl_boot\n" \
++" .type _dl_boot,@function\n" \
++"_dl_boot:\n" \
++" move.d $sp,$r10\n" \
++" move.d $pc,$r9\n" \
++" add.d _dl_boot2 - ., $r9\n" \
++" jsr $r9\n" \
++);
++
++#define _dl_boot _dl_boot2
++#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot(X)
+diff -urN uClibc/ldso-0.9.24/ldso/cris/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/cris/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/cris/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/cris/elfinterp.c 2003-09-30 06:51:11.000000000 -0500
+@@ -0,0 +1,414 @@
++/*
++ * CRIS ELF shared library loader support.
++ *
++ * 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.
++ *
++ * Copyright (C) 2002, Axis Communications AB
++ * All rights reserved
++ *
++ * Author: Tobias Anderberg, <tobiasa@axis.com>
++ *
++ * 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.
++ */
++
++/* Support for the LD_DEBUG variable. */
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] = {
++ [0] "R_CRIS_NONE", "R_CRIS_8", "R_CRIS_16", "R_CRIS_32",
++ [4] "R_CRIS_8_PCREL", "R_CRIS_16_PCREL", "R_CRIS_32_PCREL", "R_CRIS_GNU_VTINHERIT",
++ [8] "R_CRIS_GNU_VTENTRY", "R_CRIS_COPY", "R_CRIS_GLOB_DAT", "R_CRIS_JUMP_SLOT",
++ [16] "R_CRIS_RELATIVE", "R_CRIS_16_GOT", "R_CRIS_32_GOT", "R_CRIS_16_GOTPLT",
++ [32] "R_CRIS_32_GOTPLT", "R_CRIS_32_GOTREL", "R_CRIS_32_PLT_GOTREL", "R_CRIS_32_PLT_PCREL",
++
++};
++
++
++static const char *
++_dl_reltypes(int type)
++{
++ const char *str;
++ static char buf[22];
++
++ if (type >= (sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ str = _dl_simple_ltoa(buf, (unsigned long) (type));
++
++ return str;
++}
++
++static void
++debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
++{
++ if (_dl_debug_symbols) {
++ if (symtab_index) {
++ _dl_dprintf(_dl_debug_file,
++ "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static void
++debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
++{
++ if (_dl_debug_reloc) {
++ int symtab_index;
++ const char *sym;
++
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++ if (_dl_debug_symbols)
++ _dl_dprintf(_dl_debug_file, "\n\t");
++ else
++ _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
++
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend);
++#else
++ _dl_dprintf(_dl_debug_file, "%s\toffset%x\n",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset);
++#endif
++ }
++}
++#endif /* __SUPPORT_LD_DEBUG__ */
++
++/* Defined in resolve.S. */
++extern int _dl_linux_resolv(void);
++
++unsigned long
++_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ int symtab_index;
++ char *strtab;
++ char *symname;
++ char *new_addr;
++ char *rel_addr;
++ char **got_addr;
++ Elf32_Sym *symtab;
++ ELF_RELOC *this_reloc;
++ unsigned long instr_addr;
++
++ rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
++
++ this_reloc = (ELF_RELOC *) (intptr_t)(rel_addr + reloc_entry);
++ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
++ symtab_index = ELF32_R_SYM(this_reloc->r_info);
++
++ symtab = (Elf32_Sym *) (intptr_t)(tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (reloc_type != R_CRIS_JUMP_SLOT) {
++ _dl_dprintf(2, "%s: Incorrect relocation type for jump relocations.\n",
++ _dl_progname);
++ _dl_exit(1);
++ }
++
++ /* Fetch the address of the jump instruction to fix up. */
++ instr_addr = ((unsigned long) this_reloc->r_offset + (unsigned long) tpnt->loadaddr);
++ got_addr = (char **) instr_addr;
++
++ /* Fetch the address of the GOT entry. */
++ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
++
++ if (!new_addr) {
++ new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
++
++ if (new_addr)
++ return (unsigned long) new_addr;
++
++ _dl_dprintf(2, "%s: Can't resolv symbol '%s'\n", _dl_progname, symname);
++ _dl_exit(1);
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if (_dl_debug_bindings) {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
++
++ if (_dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
++ }
++#endif
++
++ *got_addr = new_addr;
++ return (unsigned long) new_addr;
++}
++
++static int
++_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long rel_addr,
++ unsigned long rel_size, int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
++{
++ int symtab_index;
++ int res;
++ unsigned int i;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rpnt;
++
++ /* Parse the relocation information. */
++ rpnt = (ELF_RELOC *) (intptr_t) (rel_addr + tpnt->loadaddr);
++ rel_size /= sizeof(ELF_RELOC);
++
++ symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++ for (i = 0; i < rel_size; i++, rpnt++) {
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++
++ /*
++ * Make sure the same symbols that the linker resolved when it
++ * bootstapped itself isn't resolved 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;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab, strtab, symtab_index);
++ debug_reloc(symtab, strtab, rpnt);
++#endif
++
++ /* Pass over to actual relocation function. */
++ res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab);
++
++ if (res == 0)
++ continue;
++
++ _dl_dprintf(2, "\n%s: ", _dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++ if (res < 0) {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle relocation type '%s'\n", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle relocation type %x\n", reloc_type);
++#endif
++ _dl_exit(-res);
++ }
++ else if (res > 0) {
++ _dl_dprintf(2, "can't resolv symbol\n");
++ return res;
++ }
++ }
++
++ return 0;
++}
++
++static int
++_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
++ Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ char *symname;
++ unsigned long *reloc_addr;
++ unsigned symbol_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++
++ reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++ if (symtab[symtab_index].st_shndx != SHN_UNDEF &&
++ ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) {
++ symbol_addr = (unsigned long) tpnt->loadaddr;
++ }
++ else {
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
++ (reloc_type == R_CRIS_JUMP_SLOT ? tpnt : NULL), symbolrel);
++ }
++
++ if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
++ symname, tpnt->libname);
++#endif
++ return 0;
++ }
++
++ symbol_addr += rpnt->r_addend;
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++
++ switch (reloc_type) {
++ case R_CRIS_NONE:
++ break;
++ case R_CRIS_GLOB_DAT:
++ case R_CRIS_JUMP_SLOT:
++ case R_CRIS_32:
++ case R_CRIS_COPY:
++ *reloc_addr = symbol_addr;
++ break;
++ case R_CRIS_RELATIVE:
++ *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
++ break;
++ default:
++ return -1; /* Call _dl_exit(1). */
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if (_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++static int
++_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
++ Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ unsigned long *reloc_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++
++ /* Don't care about these, just keep the compiler happy. */
++ (void) scope;
++ (void) symtab;
++ (void) strtab;
++
++ reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++
++ switch (reloc_type) {
++ case R_CRIS_NONE:
++ break;
++ case R_CRIS_JUMP_SLOT:
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ break;
++ default:
++ return -1; /* Calls _dl_exit(1). */
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if (_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++static int
++_dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
++ Elf32_Sym *symtab, char *strtab)
++{
++ int goof;
++ int reloc_type;
++ int symtab_index;
++ char *symname;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++ if (reloc_type != R_CRIS_COPY)
++ return 0;
++
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++ goof = 0;
++
++ if (symtab_index) {
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
++
++ if (!symbol_addr)
++ goof++;
++ }
++
++ if (!goof) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if (_dl_debug_move)
++ _dl_dprintf(_dl_debug_file, "\n%s move %x bytes from %x to %x",
++ symname, symtab[symtab_index].st_size, symbol_addr, symtab[symtab_index].st_value);
++#endif
++ _dl_memcpy((char *) symtab[symtab_index].st_value,
++ (char *) symbol_addr, symtab[symtab_index].st_size);
++ }
++
++ return goof;
++}
++
++/* External interface to the generic part of the dynamic linker. */
++
++int
++_dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ /* Keep the compiler happy. */
++ (void) type;
++ return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
++}
++void
++_dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ /* Keep the compiler happy. */
++ (void) type;
++ _dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
++}
++
++int
++_dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ /* Keep the compiler happy. */
++ (void) type;
++ return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
++}
+diff -urN uClibc/ldso-0.9.24/ldso/cris/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/cris/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/cris/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/cris/ld_syscalls.h 2002-09-23 05:37:16.000000000 -0500
+@@ -0,0 +1,7 @@
++/*
++ * Define the __set_errno macro as nothing so that INLINE_SYSCALL
++ * won't set errno, which is important since we make system calls
++ * before the errno symbol is dynamicly linked.
++ */
++#define __set_errno(X) {(void)(X);}
++#include "sys/syscall.h"
+diff -urN uClibc/ldso-0.9.24/ldso/cris/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/cris/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/cris/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/cris/ld_sysdep.h 2003-08-27 07:59:23.000000000 -0500
+@@ -0,0 +1,112 @@
++/* CRIS can never use Elf32_Rel relocations. */
++#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 long *) ARGS)
++
++/*
++ * Initialization sequence for a GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[1] = (unsigned long) MODULE; \
++ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
++}
++
++/*
++ * 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_CRIS_GLOB_DAT: \
++ case R_CRIS_JUMP_SLOT: \
++ case R_CRIS_32: \
++ *REL = SYMBOL; \
++ break; \
++ case R_CRIS_16_PCREL: \
++ *(short *) *REL = SYMBOL + (RELP)->r_addend - *REL - 2; \
++ break; \
++ case R_CRIS_32_PCREL: \
++ *REL = SYMBOL + (RELP)->r_addend - *REL - 4; \
++ break; \
++ case R_CRIS_NONE: \
++ break; \
++ case R_CRIS_RELATIVE: \
++ *REL = (unsigned long) LOAD + (RELP)->r_addend; \
++ break; \
++ default: \
++ _dl_exit(1); \
++ break; \
++ }
++
++/*
++ * Transfer control to the user's application once the dynamic loader
++ * is done. This routine has to exit the current function, then call
++ * _dl_elf_main.
++ */
++#define START() __asm__ volatile ("moveq 0,$r8\n\t" \
++ "move $r8,$srp\n\t" \
++ "move.d %1,$sp\n\t" \
++ "jump %0\n\t" \
++ : : "r" (_dl_elf_main), "r" (args))
++
++/* Defined some magic numbers that this ld.so should accept. */
++#define MAGIC1 EM_CRIS
++#undef MAGIC2
++#define ELF_TARGET "CRIS"
++
++struct elf_resolve;
++extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry);
++
++/* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
++static inline unsigned long
++cris_mod(unsigned long m, unsigned long p)
++{
++ unsigned long i, t, inc;
++
++ i = p;
++ t = 0;
++
++ while (!(i & (1 << 31))) {
++ i <<= 1;
++ t++;
++ }
++
++ t--;
++
++ for (inc = t; inc > 2; inc--) {
++ i = p << inc;
++
++ if (i & (1 << 31))
++ break;
++
++ while (m >= i) {
++ m -= i;
++ i <<= 1;
++ if (i & (1 << 31))
++ break;
++ if (i < p)
++ break;
++ }
++ }
++
++ while (m >= p)
++ m -= p;
++
++ return m;
++}
++
++#define do_rem(result, n, base) result = cris_mod(n, base);
++
++/* 8192 bytes alignment */
++#define PAGE_ALIGN 0xffffe000
++#define ADDR_ALIGN 0x1fff
++#define OFFS_ALIGN 0xffffe000
+diff -urN uClibc/ldso-0.9.24/ldso/cris/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/cris/resolve.S
+--- uClibc/ldso-0.9.24/ldso/cris/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/cris/resolve.S 2002-09-16 03:11:43.000000000 -0500
+@@ -0,0 +1,48 @@
++/*
++ * This function is _not_ called directly. It is jumped to from PLT when
++ * attempting to use a symbol that has not yet been resolved. The first
++ * time a jump symbol (such as a function call inside a shared library)
++ * is used (before it gets resolved) it will jump here. When we get called
++ * the stack contains reloc_offset and tpnt is in MOF.
++ *
++ * We save all the registers, setup R10 and R11 with the right arguments
++ * then call _dl_linux_resolver(tpnt, reloc_offset). _dl_linux_resolver()
++ * figures out where the jump symbol is _really_ supposed to have jumped to
++ * and returns that to us. Once we have that, we overwrite tpnt with this
++ * fixed up address. We then clean up after ourselves, put all the registers
++ * back how we found them, then we jump to where the fixed up address, which
++ * is where the jump symbol that got us here really wanted to jump to in the
++ * first place.
++ */
++
++.globl _dl_linux_resolve
++.type _dl_linux_resolve,@function
++
++_dl_linux_resolve:
++ push $r13
++ push $r12
++ push $r11
++ push $r10
++ push $r9
++ push $srp
++ move.d [$sp+6*4],$r11
++ move $mof,$r10
++#ifdef __PIC__
++ move.d $pc,$r0
++ sub.d .:GOTOFF,$r0
++ move.d _dl_linux_resolver:PLTG,$r9
++ add.d $r0,$r9
++ jsr $r9
++#else
++ jsr _dl_linux_resolver
++#endif
++ move.d $r10,[$sp+6*4]
++ pop $srp
++ pop $r9
++ pop $r10
++ pop $r11
++ pop $r12
++ pop $r13
++ jump [$sp+]
++
++ .size _dl_linux_resolve, . - _dl_linux_resolve
+diff -urN uClibc/ldso-0.9.24/ldso/hash.c uClibc.ldso.24/ldso-0.9.24/ldso/hash.c
+--- uClibc/ldso-0.9.24/ldso/hash.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/hash.c 2003-08-19 08:11:06.000000000 -0500
+@@ -0,0 +1,327 @@
++/* vi: set sw=4 ts=4: */
++/* Program to load an ELF binary on a linux system, and run it
++ * after resolving ELF shared library symbols
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ * Copyright (C) 2001-2002, Erik Andersen
++ *
++ * 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.
++ */
++
++
++/* Various symbol table handling functions, including symbol lookup */
++
++/*
++ * This is the start of the linked list that describes all of the files present
++ * in the system with pointers to all of the symbol, string, and hash tables,
++ * as well as all of the other good stuff in the binary.
++ */
++
++struct elf_resolve *_dl_loaded_modules = NULL;
++
++/*
++ * This is the list of modules that are loaded when the image is first
++ * started. As we add more via dlopen, they get added into other
++ * chains.
++ */
++struct dyn_elf *_dl_symbol_tables = NULL;
++
++/*
++ * This is the list of modules that are loaded via dlopen. We may need
++ * to search these for RTLD_GLOBAL files.
++ */
++struct dyn_elf *_dl_handles = NULL;
++
++
++/*
++ * This is the hash function that is used by the ELF linker to generate
++ * the hash table that each executable and library is required to
++ * have. We need it to decode the hash table.
++ */
++
++unsigned long _dl_elf_hash(const char *name)
++{
++ unsigned long hash = 0;
++ unsigned long tmp;
++
++ while (*name) {
++ hash = (hash << 4) + *name++;
++ if ((tmp = hash & 0xf0000000))
++ hash ^= tmp >> 24;
++ hash &= ~tmp;
++ };
++ return hash;
++}
++
++/*
++ * Check to see if a library has already been added to the hash chain.
++ */
++struct elf_resolve *_dl_check_hashed_files(const char *libname)
++{
++ struct elf_resolve *tpnt;
++ int len = _dl_strlen(libname);
++
++ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
++ if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
++ (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
++ return tpnt;
++ }
++
++ return NULL;
++}
++
++/*
++ * We call this function when we have just read an ELF library or executable.
++ * We add the relevant info to the symbol chain, so that we can resolve all
++ * externals properly.
++ */
++
++struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
++ char *loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr,
++ unsigned long dynamic_size)
++{
++ unsigned long *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(struct elf_resolve));
++ } 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(struct elf_resolve));
++ tpnt->next->prev = tpnt;
++ tpnt = tpnt->next;
++ };
++
++ tpnt->next = NULL;
++ tpnt->init_flag = 0;
++ tpnt->libname = _dl_strdup(libname);
++ tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
++ tpnt->dynamic_size = dynamic_size;
++ tpnt->libtype = loaded_file;
++
++ if (dynamic_info[DT_HASH] != 0) {
++ hash_addr = (unsigned long *) (intptr_t)(dynamic_info[DT_HASH] + loadaddr);
++ tpnt->nbucket = *hash_addr++;
++ tpnt->nchain = *hash_addr++;
++ tpnt->elf_buckets = hash_addr;
++ hash_addr += tpnt->nbucket;
++ tpnt->chains = hash_addr;
++ }
++ tpnt->loadaddr = (ElfW(Addr))loadaddr;
++ for (i = 0; i < 24; i++)
++ tpnt->dynamic_info[i] = dynamic_info[i];
++#ifdef __mips__
++ {
++ Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr;
++
++ while(dpnt->d_tag) {
++ if (dpnt->d_tag == DT_MIPS_GOTSYM)
++ tpnt->mips_gotsym = dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
++ tpnt->mips_local_gotno = dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_SYMTABNO)
++ tpnt->mips_symtabno = dpnt->d_un.d_val;
++ dpnt++;
++ }
++ }
++#endif
++ 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(const char *name, struct dyn_elf *rpnt1,
++ struct elf_resolve *f_tpnt, enum caller_type caller_type)
++{
++ struct elf_resolve *tpnt;
++ int si;
++ char *pnt;
++ int pass;
++ char *strtab;
++ Elf32_Sym *symtab;
++ unsigned long elf_hash_number, hn;
++ char *weak_result;
++ struct elf_resolve *first_def;
++ struct dyn_elf *rpnt, first;
++ char *data_result = 0; /* nakao */
++
++ weak_result = 0;
++ elf_hash_number = _dl_elf_hash(name);
++
++ /* A quick little hack to make sure that any symbol in the executable
++ will be preferred to one in a shared library. This is necessary so
++ that any shared library data symbols referenced in the executable
++ will be seen at the same address by the executable, shared libraries
++ and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
++ if (_dl_symbol_tables && !caller_type && rpnt1) {
++ first = (*_dl_symbol_tables);
++ first.next = rpnt1;
++ rpnt1 = (&first);
++ }
++
++ /*
++ * The passes are so that we can first search the regular symbols
++ * for whatever module was specified, and then search anything
++ * loaded with RTLD_GLOBAL. When pass is 1, it means we are just
++ * starting the first dlopened module, and anything above that
++ * is just the next one in the chain.
++ */
++ for (pass = 0; (1 == 1); pass++) {
++
++ /*
++ * If we are just starting to search for RTLD_GLOBAL, setup
++ * the pointer for the start of the search.
++ */
++ if (pass == 1) {
++ rpnt1 = _dl_handles;
++ }
++
++ /*
++ * Anything after this, we need to skip to the next module.
++ */
++ else if (pass >= 2) {
++ rpnt1 = rpnt1->next_handle;
++ }
++
++ /*
++ * Make sure we still have a module, and make sure that this
++ * module was loaded with RTLD_GLOBAL.
++ */
++ if (pass != 0) {
++ if (rpnt1 == NULL)
++ break;
++ if ((rpnt1->flags & RTLD_GLOBAL) == 0)
++ continue;
++ }
++
++ for (rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); rpnt; rpnt = rpnt->next) {
++ tpnt = rpnt->dyn;
++
++ /*
++ * The idea here is that if we are using dlsym, we want to
++ * first search the entire chain loaded from dlopen, and
++ * return a result from that if we found anything. If this
++ * fails, then we continue the search into the stuff loaded
++ * when the image was activated. For normal lookups, we start
++ * with rpnt == NULL, so we should never hit this.
++ */
++ if (tpnt->libtype == elf_executable && weak_result != 0) {
++ break;
++ }
++
++ /*
++ * Avoid calling .urem here.
++ */
++ do_rem(hn, elf_hash_number, tpnt->nbucket);
++ symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ /*
++ * This crap is required because the first instance of a
++ * symbol on the chain will be used for all symbol references.
++ * Thus this instance must be resolved to an address that
++ * contains the actual function,
++ */
++
++ first_def = NULL;
++
++ for (si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]) {
++ pnt = strtab + symtab[si].st_name;
++
++ if (_dl_strcmp(pnt, name) == 0 &&
++ symtab[si].st_value != 0)
++ {
++ if ((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_shndx != SHN_UNDEF) {
++
++ /* Here we make sure that we find a module where the symbol is
++ * actually defined.
++ */
++
++ if (f_tpnt) {
++ if (!first_def)
++ first_def = tpnt;
++ if (first_def == f_tpnt
++ && symtab[si].st_shndx == 0)
++ continue;
++ }
++
++ switch (ELF32_ST_BIND(symtab[si].st_info)) {
++ case STB_GLOBAL:
++ if (tpnt->libtype != elf_executable &&
++ ELF32_ST_TYPE(symtab[si].st_info)
++ == STT_NOTYPE)
++ { /* nakao */
++ data_result = (char *)tpnt->loadaddr +
++ symtab[si].st_value; /* nakao */
++ break; /* nakao */
++ } else /* nakao */
++ return (char*)tpnt->loadaddr + symtab[si].st_value;
++ case STB_WEAK:
++ if (!weak_result)
++ weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
++ break;
++ default: /* Do local symbols need to be examined? */
++ break;
++ }
++ }
++#ifndef __mips__
++ /*
++ * References to the address of a function from an executable file and
++ * the shared objects associated with it might not resolve to the same
++ * value. To allow comparisons of function addresses we must resolve
++ * to the address of the plt entry of the executable instead of the
++ * real function address.
++ * see "TIS ELF Specification Version 1.2, Book 3, A-11 (Function
++ * Adresses)
++ */
++ if (resolver != caller_type &&
++ NULL==f_tpnt && /*trick: don't handle R_??_JMP_SLOT reloc type*/
++ tpnt->libtype == elf_executable &&
++ ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC &&
++ symtab[si].st_shndx == SHN_UNDEF)
++ {
++ return (char*)symtab[si].st_value;
++ }
++#endif
++ }
++ }
++ }
++ }
++ if (data_result)
++ return data_result; /* nakao */
++ return weak_result;
++}
+diff -urN uClibc/ldso-0.9.24/ldso/i386/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/i386/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/i386/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/i386/boot1_arch.h 2002-08-08 09:35:31.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. See arm/boot1_arch.h for an example of what
++ * can be done.
++ */
++
++#define LD_BOOT(X) void _dl_boot (X)
+diff -urN uClibc/ldso-0.9.24/ldso/i386/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/i386/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/i386/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/i386/elfinterp.c 2003-11-06 16:09:38.000000000 -0600
+@@ -0,0 +1,415 @@
++/* vi: set sw=4 ts=4: */
++/* i386 ELF shared library loader suppport
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ * Copyright (C) 2001-2002, Erik Andersen
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] =
++{
++ [0] "R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32",
++ [4] "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT",
++ [8] "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC",
++};
++
++static const char *
++_dl_reltypes(int type)
++{
++ static char buf[22];
++ const char *str;
++
++ if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ {
++ str =_dl_simple_ltoa( buf, (unsigned long)(type));
++ }
++ return str;
++}
++
++static
++void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
++{
++ if(_dl_debug_symbols)
++ {
++ if(symtab_index){
++ _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
++{
++ if(_dl_debug_reloc)
++ {
++ int symtab_index;
++ const char *sym;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++ if(_dl_debug_symbols)
++ _dl_dprintf(_dl_debug_file, "\n\t");
++ else
++ _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend);
++#else
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset);
++#endif
++ }
++}
++#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. */
++
++extern int _dl_linux_resolve(void);
++
++unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ ELF_RELOC *this_reloc;
++ char *strtab;
++ Elf32_Sym *symtab;
++ int symtab_index;
++ char *rel_addr;
++ char *new_addr;
++ char **got_addr;
++ unsigned long instr_addr;
++ char *symname;
++
++ rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
++
++ this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
++ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
++ symtab_index = ELF32_R_SYM(this_reloc->r_info);
++
++ symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ symname= strtab + symtab[symtab_index].st_name;
++
++ if (reloc_type != R_386_JMP_SLOT) {
++ _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
++ _dl_progname);
++ _dl_exit(1);
++ }
++
++ /* Address of jump instruction to fix up */
++ instr_addr = ((unsigned long) this_reloc->r_offset +
++ (unsigned long) tpnt->loadaddr);
++ got_addr = (char **) instr_addr;
++
++ /* Get the address of the GOT entry */
++ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
++ if (!new_addr) {
++ new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
++ if (new_addr) {
++ return (unsigned long) new_addr;
++ }
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
++ _dl_exit(1);
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if ((unsigned long) got_addr < 0x40000000)
++ {
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
++ }
++ }
++ if (!_dl_debug_nofixups) {
++ *got_addr = new_addr;
++ }
++#else
++ *got_addr = new_addr;
++#endif
++
++ return (unsigned long) new_addr;
++}
++
++static int
++_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
++ unsigned long rel_addr, unsigned long rel_size,
++ int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
++{
++ unsigned int i;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rpnt;
++ int symtab_index;
++
++ /* Now parse the relocation information */
++ rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof(ELF_RELOC);
++
++ symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++ for (i = 0; i < rel_size; i++, rpnt++) {
++ int res;
++
++ 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;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,rpnt);
++#endif
++
++ res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
++
++ if (res==0) continue;
++
++ _dl_dprintf(2, "\n%s: ",_dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++ if (res <0)
++ {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
++#endif
++ _dl_exit(-res);
++ }
++ else if (res >0)
++ {
++ _dl_dprintf(2, "can't resolve symbol\n");
++ return res;
++ }
++ }
++ return 0;
++}
++
++
++static int
++_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ char *symname;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
++ (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
++
++ /*
++ * 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) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
++ symname, tpnt->libname);
++#endif
++ return 0;
++ }
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++ 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 long) 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 long) tpnt->loadaddr;
++ break;
++ case R_386_COPY:
++ /* handled later on */
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++static int
++_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ unsigned long *reloc_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++ (void)scope;
++ (void)symtab;
++ (void)strtab;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_386_NONE:
++ break;
++ case R_386_JMP_SLOT:
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++ return 0;
++
++}
++
++/* 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 */
++static int
++_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int goof = 0;
++ char *symname;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ if (reloc_type != R_386_COPY)
++ return 0;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
++ if (!symbol_addr) goof++;
++ }
++ if (!goof) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_move)
++ _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
++ symname, symtab[symtab_index].st_size,
++ symbol_addr, symtab[symtab_index].st_value);
++#endif
++ _dl_memcpy((char *) symtab[symtab_index].st_value,
++ (char *) symbol_addr, symtab[symtab_index].st_size);
++ }
++
++ return goof;
++}
++
++void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
++}
++
++int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
++}
++
++int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
++}
++
+diff -urN uClibc/ldso-0.9.24/ldso/i386/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/i386/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/i386/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/i386/ld_syscalls.h 2002-08-09 07:20:21.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Define the __set_errno macro as nothing so that INLINE_SYSCALL
++ * won't set errno, which is important since we make system calls
++ * before the errno symbol is dynamicly linked. */
++
++#define __set_errno(X) {(void)(X);}
++#include "sys/syscall.h"
++
+diff -urN uClibc/ldso-0.9.24/ldso/i386/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/i386/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/i386/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/i386/ld_sysdep.h 2002-05-28 16:33:32.000000000 -0500
+@@ -0,0 +1,81 @@
++/*
++ * 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 long*) & ARGS)
++
++/*
++ * Initialization sequence for a GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
++ GOT_BASE[1] = (unsigned long) 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 long) REL; \
++ break; \
++ case R_386_GLOB_DAT: \
++ case R_386_JMP_SLOT: \
++ *REL = SYMBOL; \
++ break; \
++ case R_386_RELATIVE: \
++ *REL += (unsigned long) LOAD; \
++ break; \
++ default: \
++ _dl_exit(1); \
++ }
++
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. This routine has to exit the current function, then
++ * call the _dl_elf_main function.
++ */
++#define START() \
++ __asm__ volatile ("leave\n\t" \
++ "jmp *%%eax\n\t" \
++ : "=a" (status) : "a" (_dl_elf_main))
++
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_386
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "386"
++
++struct elf_resolve;
++extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
++
++#define do_rem(result, n, base) result = (n % base)
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/i386/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/i386/resolve.S
+--- uClibc/ldso-0.9.24/ldso/i386/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/i386/resolve.S 2001-06-14 16:51:51.000000000 -0500
+@@ -0,0 +1,52 @@
++/*
++ * This function is _not_ called directly. It is jumped to (so no return
++ * address is on the stack) when attempting to use a symbol that has not yet
++ * been resolved. The first time a jump symbol (such as a function call inside
++ * a shared library) is used (before it gets resolved) it will jump here to
++ * _dl_linux_resolve. When we get called the stack looks like this:
++ * reloc_entry
++ * tpnt
++ *
++ * This function saves all the registers, puts a copy of reloc_entry and tpnt
++ * on the stack (as function arguments) then make the function call
++ * _dl_linux_resolver(tpnt, reloc_entry). _dl_linux_resolver() figures out
++ * where the jump symbol is _really_ supposed to have jumped to and returns
++ * that to us. Once we have that, we overwrite tpnt with this fixed up
++ * address. We then clean up after ourselves, put all the registers back how we
++ * found them, then we jump to where the fixed up address, which is where the
++ * jump symbol that got us here really wanted to jump to in the first place.
++ * found them, then we jump to the fixed up address, which is where the jump
++ * symbol that got us here really wanted to jump to in the first place.
++ * -Erik Andersen
++ */
++
++.text
++.align 4
++
++.globl _dl_linux_resolve
++.type _dl_linux_resolve,@function
++
++_dl_linux_resolve:
++ pusha /* preserve all regs */
++ lea 0x20(%esp),%eax /* eax = tpnt and reloc_entry params */
++ pushl 4(%eax) /* push copy of reloc_entry param */
++ pushl (%eax) /* push copy of tpnt param */
++
++#ifdef __PIC__
++ call .L24
++.L24:
++ popl %ebx
++ addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
++ movl _dl_linux_resolver@GOT(%ebx),%ebx /* eax = resolved func */
++ call *%ebx
++#else
++ call _dl_linux_resolver
++#endif
++ movl %eax,0x28(%esp) /* store func addr over original
++ * tpnt param */
++ addl $0x8,%esp /* remove copy parameters */
++ popa /* restore regs */
++ ret $4 /* jump to func removing original
++ * reloc_entry param from stack */
++.LFE2:
++ .size _dl_linux_resolve,.LFE2-_dl_linux_resolve
+diff -urN uClibc/ldso-0.9.24/ldso/ldso.c uClibc.ldso.24/ldso-0.9.24/ldso/ldso.c
+--- uClibc/ldso-0.9.24/ldso/ldso.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/ldso.c 2003-12-05 14:24:26.000000000 -0600
+@@ -0,0 +1,1296 @@
++/* vi: set sw=4 ts=4: */
++/* Program to load an ELF binary on a linux system, and run it
++ * after resolving ELF shared library symbols
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ * Copyright (C) 2001-2002, Erik Andersen
++ *
++ * 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.
++ */
++
++// Support a list of library preloads in /etc/ld.so.preload
++//#define SUPPORT_LDSO_PRELOAD_FILE
++
++
++/* 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 or call any functions. No globals initially, since the
++ * Global Offset Table (GOT) is initialized by the linker assuming a
++ * virtual address of 0, and no function calls initially since the
++ * Procedure Linkage Table (PLT) is not yet initialized.
++ *
++ * There are additional initial 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.
++ *
++ * 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 to override symbols (i.e. weak symbols and/or
++ * LD_PRELOAD). So initially, we only perform 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 Auxiliary Vector Table information sitting on
++ * which is provided to us by the kernel, and 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 auxvt. For details see linux/fs/binfmt_elf.c where it calls
++ * NEW_AUX_ENT() a bunch of time....
++ *
++ * Next, we need to find the GOT. On most arches there is a register
++ * pointing to the GOT, but just in case (and for new ports) I've added
++ * some (slow) C code to locate the GOT for you.
++ *
++ * This code was originally written for SVr4, and there the kernel
++ * would load all text pages R/O, so they needed to call mprotect a
++ * zillion times to mark all text pages as writable so dynamic linking
++ * would succeed. Then when they were done, they would change the
++ * protections for all the pages back again. Well, under Linux
++ * everything is loaded writable (since Linux does copy on write
++ * anyways) so all the mprotect stuff has been disabled.
++ *
++ * Initially, we do not have access to _dl_malloc since we can't yet
++ * make function calls, so we mmap one page to use as scratch space.
++ * Later on, when we can call _dl_malloc we reuse this this memory.
++ * This is also beneficial, since we do not want to use the same memory
++ * pool as malloc anyway - esp if the user redefines malloc to do
++ * something funky.
++ *
++ * 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 "ldso.h"
++
++
++#define ALLOW_ZERO_PLTGOT
++
++/* Some arches may need to override this in boot1_arch.h */
++#define ELFMAGIC ELFMAG
++
++/* This is a poor man's malloc, used prior to resolving our internal poor man's malloc */
++#define LD_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ; REALIGN();
++/*
++ * 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 LD_MALLOC.
++ */
++#define REALIGN() malloc_buffer = (char *) (((unsigned long) malloc_buffer + 3) & ~(3))
++
++char *_dl_library_path = 0; /* Where we look for libraries */
++char *_dl_preload = 0; /* Things to be loaded before the libs. */
++char *_dl_ldsopath = 0;
++static int _dl_be_lazy = RTLD_LAZY;
++#ifdef __SUPPORT_LD_DEBUG__
++char *_dl_debug = 0;
++char *_dl_debug_symbols = 0;
++char *_dl_debug_move = 0;
++char *_dl_debug_reloc = 0;
++char *_dl_debug_detail = 0;
++char *_dl_debug_nofixups = 0;
++char *_dl_debug_bindings = 0;
++int _dl_debug_file = 2;
++#else
++#define _dl_debug_file 2
++#endif
++static char *_dl_malloc_addr, *_dl_mmap_zero;
++
++static char *_dl_trace_loaded_objects = 0;
++static int (*_dl_elf_main) (int, char **, char **);
++struct r_debug *_dl_debug_addr = NULL;
++unsigned long *_dl_brkp;
++unsigned long *_dl_envp;
++int _dl_fixup(struct elf_resolve *tpnt, int lazy);
++void _dl_debug_state(void);
++char *_dl_get_last_path_component(char *path);
++static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
++ unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1],
++ char **envp, struct r_debug *debug_addr);
++
++#include "boot1_arch.h"
++#include "_dl_progname.h" /* Pull in the value of _dl_progname */
++
++/* When we enter this piece of code, the program stack looks like this:
++ argc argument counter (integer)
++ argv[0] program name (pointer)
++ argv[1...N] program args (pointers)
++ argv[argc-1] end of args (integer)
++ NULL
++ env[0...N] environment variables (pointers)
++ NULL
++ auxvt[0...N] Auxiliary Vector Table elements (mixed types)
++*/
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++/* Debugging is especially tricky on PowerPC, since string literals
++ * require relocations. Thus, you can't use _dl_dprintf() for
++ * anything until the bootstrap relocations are finished. */
++static inline void hexprint(unsigned long x)
++{
++ int i;
++ char c;
++
++ for (i = 0; i < 8; i++) {
++ c = ((x >> 28) + '0');
++ if (c > '9')
++ c += 'a' - '9' - 1;
++ _dl_write(1, &c, 1);
++ x <<= 4;
++ }
++ c = '\n';
++ _dl_write(1, &c, 1);
++}
++#endif
++
++LD_BOOT(unsigned long args) __attribute__ ((unused));
++
++LD_BOOT(unsigned long args)
++{
++ unsigned int argc;
++ char **argv, **envp;
++ unsigned long load_addr;
++ unsigned long *got;
++ unsigned long *aux_dat;
++ int goof = 0;
++ ElfW(Ehdr) *header;
++ struct elf_resolve *tpnt;
++ struct elf_resolve *app_tpnt;
++ Elf32_auxv_t auxvt[AT_EGID + 1];
++ unsigned char *malloc_buffer, *mmap_zero;
++ Elf32_Dyn *dpnt;
++ unsigned long *hash_addr;
++ struct r_debug *debug_addr = NULL;
++ int indx;
++ int status;
++
++
++ /* WARNING! -- we cannot make _any_ funtion calls until we have
++ * taken care of fixing up our own relocations. Making static
++ * inline calls is ok, but _no_ function calls. Not yet
++ * anyways. */
++
++ /* First obtain the information on the stack that tells us more about
++ what binary is loaded, where it is loaded, etc, etc */
++ GET_ARGV(aux_dat, args);
++#if defined (__arm__) || defined (__mips__) || defined (__cris__)
++ aux_dat += 1;
++#endif
++ argc = *(aux_dat - 1);
++ argv = (char **) aux_dat;
++ aux_dat += argc; /* Skip over the argv pointers */
++ aux_dat++; /* Skip over NULL at end of argv */
++ envp = (char **) aux_dat;
++ while (*aux_dat)
++ aux_dat++; /* Skip over the envp pointers */
++ aux_dat++; /* Skip over NULL at end of envp */
++
++ /* Place -1 here as a checkpoint. We later check if it was changed
++ * when we read in the auxvt */
++ auxvt[AT_UID].a_type = -1;
++
++ /* The junk on the stack immediately following the environment is
++ * the Auxiliary Vector Table. Read out the elements of the auxvt,
++ * sort and store them in auxvt for later use. */
++ while (*aux_dat) {
++ Elf32_auxv_t *auxv_entry = (Elf32_auxv_t *) aux_dat;
++
++ if (auxv_entry->a_type <= AT_EGID) {
++ _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(Elf32_auxv_t));
++ }
++ aux_dat += 2;
++ }
++
++ /* locate the ELF header. We need this done as soon as possible
++ * (esp since SEND_STDERR() needs this on some platforms... */
++ load_addr = auxvt[AT_BASE].a_un.a_val;
++ header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
++
++ /* Check the ELF header to make sure everything looks ok. */
++ if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
++ header->e_ident[EI_VERSION] != EV_CURRENT
++#if !defined(__powerpc__) && !defined(__mips__) && !defined(__sh__)
++ || _dl_strncmp((void *) header, ELFMAGIC, SELFMAG) != 0
++#else
++ || header->e_ident[EI_MAG0] != ELFMAG0
++ || header->e_ident[EI_MAG1] != ELFMAG1
++ || header->e_ident[EI_MAG2] != ELFMAG2
++ || header->e_ident[EI_MAG3] != ELFMAG3
++#endif
++ ) {
++ SEND_STDERR("Invalid ELF header\n");
++ _dl_exit(0);
++ }
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("ELF header=");
++ SEND_ADDRESS_STDERR(load_addr, 1);
++#endif
++
++
++ /* Locate the global offset table. Since this code must be PIC
++ * we can take advantage of the magic offset register, if we
++ * happen to know what that is for this architecture. If not,
++ * we can always read stuff out of the ELF file to find it... */
++#if defined(__i386__)
++ __asm__("\tmovl %%ebx,%0\n\t":"=a"(got));
++#elif defined(__m68k__)
++ __asm__("movel %%a5,%0":"=g"(got))
++#elif defined(__sparc__)
++ __asm__("\tmov %%l7,%0\n\t":"=r"(got))
++#elif defined(__arm__)
++ __asm__("\tmov %0, r10\n\t":"=r"(got));
++#elif defined(__powerpc__)
++ __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4@local\n\t":"=l"(got));
++#elif defined(__mips__)
++ __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
++#elif defined(__sh__)
++ __asm__(
++" mov.l 1f, %0\n"
++" mova 1f, r0\n"
++" bra 2f\n"
++" add r0, %0\n"
++" .balign 4\n"
++"1: .long _GLOBAL_OFFSET_TABLE_\n"
++"2:" : "=r" (got) : : "r0");
++#elif defined(__cris__)
++ __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got));
++#else
++ /* Do things the slow way in C */
++ {
++ unsigned long tx_reloc;
++ Elf32_Dyn *dynamic = NULL;
++ Elf32_Shdr *shdr;
++ Elf32_Phdr *pt_load;
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("Finding the GOT using C code to read the ELF file\n");
++#endif
++ /* Find where the dynamic linking information section is hiding */
++ shdr = (Elf32_Shdr *) (header->e_shoff + (char *) header);
++ for (indx = header->e_shnum; --indx >= 0; ++shdr) {
++ if (shdr->sh_type == SHT_DYNAMIC) {
++ goto found_dynamic;
++ }
++ }
++ SEND_STDERR("missing dynamic linking information section \n");
++ _dl_exit(0);
++
++ found_dynamic:
++ dynamic = (Elf32_Dyn *) (shdr->sh_offset + (char *) header);
++
++ /* Find where PT_LOAD is hiding */
++ pt_load = (Elf32_Phdr *) (header->e_phoff + (char *) header);
++ for (indx = header->e_phnum; --indx >= 0; ++pt_load) {
++ if (pt_load->p_type == PT_LOAD) {
++ goto found_pt_load;
++ }
++ }
++ SEND_STDERR("missing loadable program segment\n");
++ _dl_exit(0);
++
++ found_pt_load:
++ /* Now (finally) find where DT_PLTGOT is hiding */
++ tx_reloc = pt_load->p_vaddr - pt_load->p_offset;
++ for (; DT_NULL != dynamic->d_tag; ++dynamic) {
++ if (dynamic->d_tag == DT_PLTGOT) {
++ goto found_got;
++ }
++ }
++ SEND_STDERR("missing global offset table\n");
++ _dl_exit(0);
++
++ found_got:
++ got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc +
++ (char *) header);
++ }
++#endif
++
++ /* Now, finally, fix up the location of the dynamic stuff */
++ dpnt = (Elf32_Dyn *) (*got + load_addr);
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("First Dynamic section entry=");
++ SEND_ADDRESS_STDERR(dpnt, 1);
++#endif
++
++
++ /* Call mmap to get a page of writable memory that can be used
++ * for _dl_malloc throughout the shared lib loader. */
++ mmap_zero = malloc_buffer = _dl_mmap((void *) 0, 4096,
++ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
++ if (_dl_mmap_check_error(mmap_zero)) {
++ SEND_STDERR("dl_boot: mmap of a spare page failed!\n");
++ _dl_exit(13);
++ }
++
++ tpnt = LD_MALLOC(sizeof(struct elf_resolve));
++ _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
++ app_tpnt = LD_MALLOC(sizeof(struct elf_resolve));
++ _dl_memset(app_tpnt, 0, sizeof(struct elf_resolve));
++
++ /*
++ * This is used by gdb to locate the chain of shared libraries that are currently loaded.
++ */
++ debug_addr = LD_MALLOC(sizeof(struct r_debug));
++ _dl_memset(debug_addr, 0, sizeof(struct r_debug));
++
++ /* 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 */
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("scanning DYNAMIC section\n");
++#endif
++ while (dpnt->d_tag) {
++#if defined(__mips__)
++ if (dpnt->d_tag == DT_MIPS_GOTSYM)
++ tpnt->mips_gotsym = (unsigned long) dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
++ tpnt->mips_local_gotno = (unsigned long) dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_SYMTABNO)
++ tpnt->mips_symtabno = (unsigned long) dpnt->d_un.d_val;
++#endif
++ if (dpnt->d_tag < 24) {
++ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_TEXTREL) {
++ tpnt->dynamic_info[DT_TEXTREL] = 1;
++ }
++ }
++ dpnt++;
++ }
++
++ {
++ ElfW(Phdr) *ppnt;
++ int i;
++
++ ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
++ for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
++ if (ppnt->p_type == PT_DYNAMIC) {
++ dpnt = (Elf32_Dyn *) ppnt->p_vaddr;
++ while (dpnt->d_tag) {
++#if defined(__mips__)
++ if (dpnt->d_tag == DT_MIPS_GOTSYM)
++ app_tpnt->mips_gotsym =
++ (unsigned long) dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
++ app_tpnt->mips_local_gotno =
++ (unsigned long) dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_MIPS_SYMTABNO)
++ app_tpnt->mips_symtabno =
++ (unsigned long) dpnt->d_un.d_val;
++ if (dpnt->d_tag > DT_JMPREL) {
++ dpnt++;
++ continue;
++ }
++ app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
++
++#warning "Debugging threads on mips won't work till someone fixes this..."
++#if 0
++ if (dpnt->d_tag == DT_DEBUG) {
++ dpnt->d_un.d_val = (unsigned long) debug_addr;
++ }
++#endif
++
++#else
++ if (dpnt->d_tag > DT_JMPREL) {
++ dpnt++;
++ continue;
++ }
++ app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_DEBUG) {
++ dpnt->d_un.d_val = (unsigned long) debug_addr;
++ }
++#endif
++ if (dpnt->d_tag == DT_TEXTREL)
++ app_tpnt->dynamic_info[DT_TEXTREL] = 1;
++ dpnt++;
++ }
++ }
++ }
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("done scanning DYNAMIC section\n");
++#endif
++
++ /* Get some more of the information that we will need to dynamicly link
++ this module to itself */
++
++ hash_addr = (unsigned long *) (tpnt->dynamic_info[DT_HASH] + load_addr);
++ tpnt->nbucket = *hash_addr++;
++ tpnt->nchain = *hash_addr++;
++ tpnt->elf_buckets = hash_addr;
++ hash_addr += tpnt->nbucket;
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("done grabbing link information\n");
++#endif
++
++#ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
++ /* Ugly, ugly. We need to call mprotect to change the protection of
++ the text pages so that we can do the dynamic linking. We can set the
++ protection back again once we are done */
++
++ {
++ ElfW(Phdr) *ppnt;
++ int i;
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("calling mprotect on the shared library/dynamic linker\n");
++#endif
++
++ /* First cover the shared library/dynamic linker. */
++ if (tpnt->dynamic_info[DT_TEXTREL]) {
++ header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
++ ppnt = (ElfW(Phdr) *) ((int)auxvt[AT_BASE].a_un.a_ptr +
++ header->e_phoff);
++ for (i = 0; i < header->e_phnum; i++, ppnt++) {
++ if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
++ _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & PAGE_ALIGN)),
++ (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
++ PROT_READ | PROT_WRITE | PROT_EXEC);
++ }
++ }
++ }
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("calling mprotect on the application program\n");
++#endif
++ /* Now cover the application program. */
++ if (app_tpnt->dynamic_info[DT_TEXTREL]) {
++ ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
++ for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
++ if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
++ _dl_mprotect((void *) (ppnt->p_vaddr & PAGE_ALIGN),
++ (ppnt->p_vaddr & ADDR_ALIGN) +
++ (unsigned long) ppnt->p_filesz,
++ PROT_READ | PROT_WRITE | PROT_EXEC);
++ }
++ }
++ }
++#endif
++
++#if defined(__mips__)
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("About to do MIPS specific GOT bootstrap\n");
++#endif
++ /* For MIPS we have to do stuff to the GOT before we do relocations. */
++ PERFORM_BOOTSTRAP_GOT(got);
++#endif
++
++ /* OK, now do the relocations. We do not do a lazy binding here, so
++ that once we are done, we have considerably more flexibility. */
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("About to do library loader relocations\n");
++#endif
++
++ goof = 0;
++ for (indx = 0; indx < 2; indx++) {
++ unsigned int i;
++ ELF_RELOC *rpnt;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int symtab_index;
++ unsigned long rel_addr, rel_size;
++
++
++#ifdef ELF_USES_RELOCA
++ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
++ dynamic_info[DT_RELA]);
++ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
++ dynamic_info[DT_RELASZ]);
++#else
++ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
++ dynamic_info[DT_REL]);
++ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
++ dynamic_info[DT_RELSZ]);
++#endif
++
++ if (!rel_addr)
++ continue;
++
++ /* Now parse the relocation information */
++ rpnt = (ELF_RELOC *) (rel_addr + load_addr);
++ for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
++ reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ if (symtab_index) {
++ char *strtab;
++ Elf32_Sym *symtab;
++
++ symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + load_addr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr);
++
++ /* We only do a partial dynamic linking right now. The user
++ is not supposed to redefine any symbols that start with
++ a '_', so we can do this with confidence. */
++ if (!_dl_symbol(strtab + symtab[symtab_index].st_name))
++ continue;
++ symbol_addr = load_addr + symtab[symtab_index].st_value;
++
++ if (!symbol_addr) {
++ /* This will segfault - you cannot call a function until
++ * we have finished the relocations.
++ */
++ SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
++ SEND_STDERR(strtab + symtab[symtab_index].st_name);
++ SEND_STDERR(" undefined.\n");
++ goof++;
++ }
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ SEND_STDERR("About to fixup symbol: ");
++ SEND_STDERR(strtab + symtab[symtab_index].st_name);
++ SEND_STDERR("\n");
++#endif
++ }
++ /*
++ * Use this machine-specific macro to perform the actual relocation.
++ */
++ PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
++ }
++ }
++
++ if (goof) {
++ _dl_exit(14);
++ }
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ /* Wahoo!!! */
++ _dl_dprintf(_dl_debug_file, "Done relocating library loader, so we can now\n\tuse globals and make function calls!\n");
++#endif
++
++ if (argv[0]) {
++ _dl_progname = argv[0];
++ }
++
++ /* 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. */
++
++ /* Make it so _dl_malloc can use the page of memory we have already
++ * allocated, so we shouldn't need to grab any more memory */
++ _dl_malloc_addr = malloc_buffer;
++ _dl_mmap_zero = mmap_zero;
++
++
++
++ /* 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. */
++ _dl_get_ready_to_run(tpnt, app_tpnt, load_addr, hash_addr, auxvt, envp, debug_addr);
++
++
++ /* Notify the debugger that all objects are now mapped in. */
++ _dl_debug_addr->r_state = RT_CONSISTENT;
++ _dl_debug_state();
++
++
++ /* OK we are done here. Turn out the lights, and lock up. */
++ _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn;
++
++ /*
++ * Transfer control to the application.
++ */
++ status = 0; /* Used on x86, but not on other arches */
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ntransfering control: %s\n\n", _dl_progname);
++#endif
++ START();
++}
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static void debug_fini (int status, void *arg)
++{
++ (void)status;
++ _dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg);
++}
++#endif
++
++static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
++ unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1],
++ char **envp, struct r_debug *debug_addr)
++{
++ ElfW(Phdr) *ppnt;
++ char *lpntstr;
++ int i, _dl_secure, goof = 0;
++ struct dyn_elf *rpnt;
++ struct elf_resolve *tcurr;
++ struct elf_resolve *tpnt1;
++ unsigned long brk_addr, *lpnt;
++ int (*_dl_atexit) (void *);
++#if defined (__SUPPORT_LD_DEBUG__)
++ int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
++#endif
++
++ /* 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 = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr);
++
++ tpnt->chains = hash_addr;
++ tpnt->next = 0;
++ tpnt->libname = 0;
++ tpnt->libtype = program_interpreter;
++ tpnt->loadaddr = (ElfW(Addr)) load_addr;
++
++#ifdef ALLOW_ZERO_PLTGOT
++ if (tpnt->dynamic_info[DT_PLTGOT])
++#endif
++ {
++ INIT_GOT(lpnt, tpnt);
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "GOT found at %x\n", lpnt);
++#endif
++ }
++
++ /* OK, this was a big step, now we need to scan all of the user images
++ and load them properly. */
++
++ {
++ ElfW(Ehdr) *epnt;
++ ElfW(Phdr) *myppnt;
++ int j;
++
++ epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
++ tpnt->n_phent = epnt->e_phnum;
++ tpnt->ppnt = myppnt = (ElfW(Phdr) *) (load_addr + epnt->e_phoff);
++ for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
++ if (myppnt->p_type == PT_DYNAMIC) {
++ tpnt->dynamic_addr = (ElfW(Dyn) *)myppnt->p_vaddr + load_addr;
++ tpnt->dynamic_size = myppnt->p_filesz;
++ }
++ }
++ }
++
++ 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 */
++
++ ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
++ for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
++ if (ppnt->p_type == PT_LOAD) {
++ if (ppnt->p_vaddr + ppnt->p_memsz > brk_addr)
++ brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
++ }
++ if (ppnt->p_type == PT_DYNAMIC) {
++#ifndef ALLOW_ZERO_PLTGOT
++ /* make sure it's really there. */
++ if (app_tpnt->dynamic_info[DT_PLTGOT] == 0)
++ continue;
++#endif
++ /* OK, we have what we need - slip this one into the list. */
++ app_tpnt = _dl_add_elf_hash_table("", 0,
++ app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
++ _dl_loaded_modules->libtype = elf_executable;
++ _dl_loaded_modules->ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
++ _dl_loaded_modules->n_phent = auxvt[AT_PHNUM].a_un.a_val;
++ _dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
++ _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
++ rpnt->dyn = _dl_loaded_modules;
++ app_tpnt->usage_count++;
++ app_tpnt->symbol_scope = _dl_symbol_tables;
++ lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]);
++#ifdef ALLOW_ZERO_PLTGOT
++ if (lpnt)
++#endif
++ INIT_GOT(lpnt, _dl_loaded_modules);
++ }
++
++ /* OK, fill this in - we did not have this before */
++ if (ppnt->p_type == PT_INTERP) {
++ int readsize = 0;
++ char *pnt, *pnt1, buf[1024];
++ tpnt->libname = _dl_strdup((char *) ppnt->p_offset +
++ (auxvt[AT_PHDR].a_un.a_val & PAGE_ALIGN));
++
++ /* Determine if the shared lib loader is a symlink */
++ _dl_memset(buf, 0, sizeof(buf));
++ readsize = _dl_readlink(tpnt->libname, buf, sizeof(buf));
++ if (readsize > 0 && readsize < (int)(sizeof(buf)-1)) {
++ pnt1 = _dl_strrchr(buf, '/');
++ if (pnt1 && buf != pnt1) {
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "changing tpnt->libname from '%s' to '%s'\n", tpnt->libname, buf);
++#endif
++ tpnt->libname = _dl_strdup(buf);
++ }
++ }
++
++ /* Store the path where the shared lib loader was found for
++ * later use */
++ pnt = _dl_strdup(tpnt->libname);
++ pnt1 = _dl_strrchr(pnt, '/');
++ if (pnt != pnt1) {
++ *pnt1 = '\0';
++ _dl_ldsopath = pnt;
++ } else {
++ _dl_ldsopath = tpnt->libname;
++ }
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Lib Loader:\t(%x) %s\n", tpnt->loadaddr, tpnt->libname);
++#endif
++ }
++ }
++
++
++ /* 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 */
++ {
++ if (_dl_getenv("LD_BIND_NOW", envp))
++ _dl_be_lazy = 0;
++
++ if ((auxvt[AT_UID].a_un.a_val == -1 && _dl_suid_ok()) ||
++ (auxvt[AT_UID].a_un.a_val != -1 &&
++ auxvt[AT_UID].a_un.a_val == auxvt[AT_EUID].a_un.a_val
++ && auxvt[AT_GID].a_un.a_val== auxvt[AT_EGID].a_un.a_val)) {
++ _dl_secure = 0;
++ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
++ _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp);
++ } else {
++ _dl_secure = 1;
++ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
++ _dl_unsetenv("LD_AOUT_PRELOAD", envp);
++ _dl_unsetenv("LD_LIBRARY_PATH", envp);
++ _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
++ _dl_library_path = NULL;
++ }
++ }
++
++#ifdef __SUPPORT_LD_DEBUG__
++ _dl_debug = _dl_getenv("LD_DEBUG", envp);
++ if (_dl_debug)
++ {
++ if (_dl_strstr(_dl_debug, "all")) {
++ _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
++ = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = _dl_strstr(_dl_debug, "all");
++ }
++ else {
++ _dl_debug_detail = _dl_strstr(_dl_debug, "detail");
++ _dl_debug_move = _dl_strstr(_dl_debug, "move");
++ _dl_debug_symbols = _dl_strstr(_dl_debug, "sym");
++ _dl_debug_reloc = _dl_strstr(_dl_debug, "reloc");
++ _dl_debug_nofixups = _dl_strstr(_dl_debug, "nofix");
++ _dl_debug_bindings = _dl_strstr(_dl_debug, "bind");
++ }
++ }
++ {
++ const char *dl_debug_output;
++
++ dl_debug_output = _dl_getenv("LD_DEBUG_OUTPUT", envp);
++
++ if (dl_debug_output)
++ {
++ char tmp[22], *tmp1, *filename;
++ int len1, len2;
++
++ _dl_memset(tmp, 0, sizeof(tmp));
++ tmp1=_dl_simple_ltoa( tmp, (unsigned long)_dl_getpid());
++
++ len1 = _dl_strlen(dl_debug_output);
++ len2 = _dl_strlen(tmp1);
++
++ filename = _dl_malloc(len1+len2+2);
++
++ if (filename)
++ {
++ _dl_strcpy (filename, dl_debug_output);
++ filename[len1] = '.';
++ _dl_strcpy (&filename[len1+1], tmp1);
++
++ _dl_debug_file= _dl_open (filename, O_WRONLY|O_CREAT);
++ if (_dl_debug_file<0)
++ {
++ _dl_debug_file = 2;
++ _dl_dprintf (2, "can't open file: '%s'\n",filename);
++ }
++ }
++ }
++ }
++
++
++#endif
++ _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
++#ifndef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects) {
++ _dl_dprintf(_dl_debug_file, "Use the ldd provided by uClibc\n");
++ _dl_exit(1);
++ }
++#endif
++
++ /*
++ * OK, fix one more thing - set up debug_addr so it will 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;
++
++ /* Notify the debugger we are in a consistant state */
++ _dl_debug_addr->r_state = RT_CONSISTENT;
++ _dl_debug_state();
++
++ /* 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. */
++
++ _dl_map_cache();
++
++
++ if (_dl_preload)
++ {
++ char c, *str, *str2;
++
++ str = _dl_preload;
++ while (*str == ':' || *str == ' ' || *str == '\t')
++ str++;
++ while (*str)
++ {
++ str2 = str;
++ while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
++ str2++;
++ c = *str2;
++ *str2 = '\0';
++ if (!_dl_secure || _dl_strchr(str, '/') == NULL)
++ {
++ if ((tpnt1 = _dl_check_if_named_library_is_loaded(str)))
++ {
++ continue;
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfile='%s'; needed by '%s'\n",
++ str, _dl_progname);
++#endif
++ tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str);
++ if (!tpnt1) {
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects)
++ _dl_dprintf(1, "\t%s => not found\n", str);
++ else
++#endif
++ {
++ _dl_dprintf(2, "%s: can't load " "library '%s'\n", _dl_progname, str);
++ _dl_exit(15);
++ }
++ } else {
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
++#endif
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
++ /* this is a real hack to make ldd not print
++ * the library itself when run on a library. */
++ if (_dl_strcmp(_dl_progname, str) != 0)
++ _dl_dprintf(1, "\t%s => %s (%x)\n", str, tpnt1->libname,
++ (unsigned) tpnt1->loadaddr);
++ }
++#endif
++ }
++ }
++ *str2 = c;
++ str = str2;
++ while (*str == ':' || *str == ' ' || *str == '\t')
++ str++;
++ }
++ }
++
++#ifdef SUPPORT_LDSO_PRELOAD_FILE
++ {
++ int fd;
++ struct stat st;
++ char *preload;
++ if (!_dl_stat(LDSO_PRELOAD, &st) && st.st_size > 0) {
++ if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
++ _dl_dprintf(2, "%s: can't open file '%s'\n",
++ _dl_progname, LDSO_PRELOAD);
++ } else {
++ preload = (caddr_t) _dl_mmap(0, st.st_size + 1,
++ PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
++ _dl_close(fd);
++ if (preload == (caddr_t) - 1) {
++ _dl_dprintf(2, "%s: can't map file '%s'\n",
++ _dl_progname, LDSO_PRELOAD);
++ } else {
++ char c, *cp, *cp2;
++
++ /* convert all separators and comments to spaces */
++ for (cp = preload; *cp; /*nada */ ) {
++ if (*cp == ':' || *cp == '\t' || *cp == '\n') {
++ *cp++ = ' ';
++ } else if (*cp == '#') {
++ do
++ *cp++ = ' ';
++ while (*cp != '\n' && *cp != '\0');
++ } else {
++ cp++;
++ }
++ }
++
++ /* find start of first library */
++ for (cp = preload; *cp && *cp == ' '; cp++)
++ /*nada */ ;
++
++ while (*cp) {
++ /* find end of library */
++ for (cp2 = cp; *cp && *cp != ' '; cp++)
++ /*nada */ ;
++ c = *cp;
++ *cp = '\0';
++
++ if ((tpnt1 = _dl_check_if_named_library_is_loaded(cp2)))
++ {
++ continue;
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfile='%s'; needed by '%s'\n",
++ cp2, _dl_progname);
++#endif
++ tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2);
++ if (!tpnt1) {
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects)
++ _dl_dprintf(1, "\t%s => not found\n", cp2);
++ else
++#endif
++ {
++ _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, cp2);
++ _dl_exit(15);
++ }
++ } else {
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
++#endif
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
++ _dl_dprintf(1, "\t%s => %s (%x)\n", cp2,
++ tpnt1->libname, (unsigned) tpnt1->loadaddr);
++ }
++#endif
++ }
++
++ /* find start of next library */
++ *cp = c;
++ for ( /*nada */ ; *cp && *cp == ' '; cp++)
++ /*nada */ ;
++ }
++
++ _dl_munmap(preload, st.st_size + 1);
++ }
++ }
++ }
++ }
++#endif
++
++ for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
++ {
++ Elf32_Dyn *dpnt;
++ for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
++ {
++ if (dpnt->d_tag == DT_NEEDED)
++ {
++ char *name;
++ lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val);
++ name = _dl_get_last_path_component(lpntstr);
++
++ if ((tpnt1 = _dl_check_if_named_library_is_loaded(name)))
++ {
++ continue;
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfile='%s'; needed by '%s'\n",
++ lpntstr, _dl_progname);
++#endif
++ if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr)))
++ {
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects) {
++ _dl_dprintf(1, "\t%s => not found\n", lpntstr);
++ continue;
++ } else
++#endif
++ {
++ _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, lpntstr);
++ _dl_exit(16);
++ }
++ } else {
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
++#endif
++#ifdef __LDSO_LDD_SUPPORT__
++ if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
++ _dl_dprintf(1, "\t%s => %s (%x)\n", lpntstr, tpnt1->libname,
++ (unsigned) tpnt1->loadaddr);
++ }
++#endif
++ }
++ }
++ }
++ }
++
++
++ _dl_unmap_cache();
++
++ /*
++ * 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) {
++ 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(struct dyn_elf));
++ rpnt->next->prev = rpnt;
++ rpnt = rpnt->next;
++ } else {
++ rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
++ _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
++ }
++ rpnt->dyn = tpnt;
++ tpnt = NULL;
++ }
++
++#ifdef __LDSO_LDD_SUPPORT__
++ /* End of the line for ldd.... */
++ if (_dl_trace_loaded_objects) {
++ _dl_dprintf(1, "\t%s => %s (%x)\n", rpnt->dyn->libname + (_dl_strlen(_dl_ldsopath)) + 1,
++ rpnt->dyn->libname, rpnt->dyn->loadaddr);
++ _dl_exit(0);
++ }
++#endif
++
++
++#ifdef __mips__
++ /*
++ * Relocation of the GOT entries for MIPS have to be done
++ * after all the libraries have been loaded.
++ */
++ _dl_perform_mips_global_got_relocations(_dl_loaded_modules);
++#endif
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Beginning relocation fixups\n");
++#endif
++ /*
++ * OK, now all of the kids are tucked into bed in their proper addresses.
++ * Now we go through and look for REL and RELA records that indicate fixups
++ * to the GOT tables. We need to do this in reverse order so that COPY
++ * directives work correctly */
++ goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules, _dl_be_lazy) : 0;
++
++
++ /* Some flavors of SVr4 do not generate the R_*_COPY directive,
++ and we have to manually search for entries that require fixups.
++ Solaris gets this one right, from what I understand. */
++
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(_dl_debug_file, "Beginning copy fixups\n");
++#endif
++ if (_dl_symbol_tables)
++ goof += _dl_copy_fixups(_dl_symbol_tables);
++
++ /* 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 long *) (intptr_t) _dl_find_hash("___brk_addr", NULL, NULL, symbolrel);
++
++ if (_dl_brkp) {
++ *_dl_brkp = brk_addr;
++ }
++ _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", NULL, NULL, symbolrel);
++
++ if (_dl_envp) {
++ *_dl_envp = (unsigned long) envp;
++ }
++
++#ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
++ {
++ unsigned int j;
++ ElfW(Phdr) *myppnt;
++
++ /* We had to set the protections of all pages to R/W for dynamic linking.
++ Set text pages back to R/O */
++ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
++ for (myppnt = tpnt->ppnt, j = 0; j < tpnt->n_phent; j++, myppnt++) {
++ if (myppnt->p_type == PT_LOAD && !(myppnt->p_flags & PF_W) && tpnt->dynamic_info[DT_TEXTREL]) {
++ _dl_mprotect((void *) (tpnt->loadaddr + (myppnt->p_vaddr & PAGE_ALIGN)),
++ (myppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) myppnt->p_filesz, LXFLAGS(myppnt->p_flags));
++ }
++ }
++ }
++
++ }
++#endif
++ _dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, NULL, symbolrel);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_on_exit = (int (*)(void (*)(int, void *),void*))
++ (intptr_t) _dl_find_hash("on_exit", NULL, NULL, symbolrel);
++#endif
++
++ /* Notify the debugger we have added some objects. */
++ _dl_debug_addr->r_state = RT_ADD;
++ _dl_debug_state();
++
++ for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
++ ;
++
++ for (;rpnt!=NULL; rpnt=rpnt->prev)
++ {
++ tpnt = rpnt->dyn;
++
++ if (tpnt->libtype == program_interpreter)
++ continue;
++
++ /* Apparently crt0/1 for the application is responsible for handling this.
++ * We only need to run the init/fini for shared libraries
++ */
++ if (tpnt->libtype == elf_executable)
++ break; /* at this point all shared libs are initialized !! */
++
++ if (tpnt->init_flag & INIT_FUNCS_CALLED)
++ continue;
++ tpnt->init_flag |= INIT_FUNCS_CALLED;
++
++ if (tpnt->dynamic_info[DT_INIT]) {
++ void (*dl_elf_func) (void);
++ dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ncalling init: %s\n\n", tpnt->libname);
++#endif
++ (*dl_elf_func) ();
++ }
++ if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
++ void (*dl_elf_func) (void);
++ dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
++ (*_dl_atexit) (dl_elf_func);
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug && _dl_on_exit)
++ {
++ (*_dl_on_exit)(debug_fini, tpnt->libname);
++ }
++#endif
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ else {
++ if (!_dl_atexit)
++ _dl_dprintf(_dl_debug_file, "%s: The address of atexit () is 0x0.\n", tpnt->libname);
++#if 0
++ if (!tpnt->dynamic_info[DT_FINI])
++ _dl_dprintf(_dl_debug_file, "%s: Invalid .fini section.\n", tpnt->libname);
++#endif
++ }
++#endif
++ }
++}
++
++/*
++ * This stub function is used by some debuggers. The idea is that they
++ * can set an internal breakpoint on it, so that we are notified when the
++ * address mapping is changed in some way.
++ */
++void _dl_debug_state(void)
++{
++}
++
++char *_dl_getenv(const char *symbol, char **envp)
++{
++ char *pnt;
++ const char *pnt1;
++
++ while ((pnt = *envp++)) {
++ pnt1 = symbol;
++ while (*pnt && *pnt == *pnt1)
++ pnt1++, pnt++;
++ if (!*pnt || *pnt != '=' || *pnt1)
++ continue;
++ return pnt + 1;
++ }
++ return 0;
++}
++
++void _dl_unsetenv(const char *symbol, char **envp)
++{
++ char *pnt;
++ const char *pnt1;
++ char **newenvp = envp;
++
++ for (pnt = *envp; pnt; pnt = *++envp) {
++ pnt1 = symbol;
++ while (*pnt && *pnt == *pnt1)
++ pnt1++, pnt++;
++ if (!*pnt || *pnt != '=' || *pnt1)
++ *newenvp++ = *envp;
++ }
++ *newenvp++ = *envp;
++ return;
++}
++
++#include "hash.c"
++#include "readelflib1.c"
+diff -urN uClibc/ldso-0.9.24/ldso/m68k/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/m68k/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/m68k/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/m68k/boot1_arch.h 2002-08-08 09:35:37.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. See arm/boot1_arch.h for an example of what
++ * can be done.
++ */
++
++#define LD_BOOT(X) void _dl_boot (X)
+diff -urN uClibc/ldso-0.9.24/ldso/m68k/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/m68k/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/m68k/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/m68k/elfinterp.c 2002-11-05 12:21:04.000000000 -0600
+@@ -0,0 +1,359 @@
++/* vi: set sw=4 ts=4: */
++/* m68k ELF shared library loader suppport
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ * Adapted to ELF/68k by Andreas Schwab.
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const 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. */
++
++
++unsigned int _dl_linux_resolver (int dummy1, int dummy2,
++ struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ Elf32_Rela *this_reloc;
++ char *strtab;
++ 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 = (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 = (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_dprintf (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 __SUPPORT_LD_DEBUG__
++ if (_dl_debug_symbols) {
++ _dl_dprintf (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, tpnt, resolver);
++ if (!new_addr)
++ {
++ _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ _dl_exit (1);
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if ((unsigned long) got_addr < 0x40000000)
++ {
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
++ strtab + symtab[symtab_index].st_name);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
++ }
++ }
++ if (!_dl_debug_nofixups) {
++ *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,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ int i;
++ char *strtab;
++ int reloc_type;
++ int symtab_index;
++ Elf32_Sym *symtab;
++ Elf32_Rela *rpnt;
++ unsigned int *reloc_addr;
++
++ /* Now parse the relocation information. */
++ rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof (Elf32_Rela);
++
++ symtab = (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_dprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if (symtab_index)
++ _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
++ _dl_dprintf (2, "\n");
++ _dl_exit (1);
++ }
++ }
++}
++
++int
++_dl_parse_relocation_information (struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ int i;
++ char *strtab;
++ int reloc_type;
++ int goof = 0;
++ Elf32_Sym *symtab;
++ Elf32_Rela *rpnt;
++ unsigned int *reloc_addr;
++ unsigned int symbol_addr;
++ int symtab_index;
++ /* Now parse the relocation information */
++
++ rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof (Elf32_Rela);
++
++ symtab = (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,
++ reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, symbolrel);
++
++ /* 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_dprintf (2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ goof++;
++ }
++ }
++ switch (reloc_type)
++ {
++ case R_68K_NONE:
++ break;
++ case R_68K_8:
++ *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_68K_16:
++ *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_68K_32:
++ *reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_68K_PC8:
++ *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
++ - (unsigned int) reloc_addr);
++ break;
++ case R_68K_PC16:
++ *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
++ - (unsigned int) reloc_addr);
++ break;
++ case R_68K_PC32:
++ *reloc_addr = (symbol_addr + rpnt->r_addend
++ - (unsigned int) reloc_addr);
++ break;
++ case R_68K_GLOB_DAT:
++ case R_68K_JMP_SLOT:
++ *reloc_addr = symbol_addr;
++ break;
++ case R_68K_RELATIVE:
++ *reloc_addr = ((unsigned int) tpnt->loadaddr
++ /* Compatibility kludge. */
++ + (rpnt->r_addend ? : *reloc_addr));
++ break;
++ case R_68K_COPY:
++#if 0 /* Do this later. */
++ _dl_dprintf (2, "Doing copy");
++ if (symtab_index)
++ _dl_dprintf (2, " for symbol %s",
++ strtab + symtab[symtab_index].st_name);
++ _dl_dprintf (2, "\n");
++ _dl_memcpy ((void *) symtab[symtab_index].st_value,
++ (void *) symbol_addr,
++ symtab[symtab_index].st_size);
++#endif
++ break;
++ default:
++ _dl_dprintf (2, "%s: can't handle reloc type ", _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf (2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if (symtab_index)
++ _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
++ _dl_dprintf (2, "\n");
++ _dl_exit (1);
++ }
++
++ }
++ return goof;
++}
++
++/* This is done as a separate step, because there are cases where
++ information is first copied and later initialized. This results in
++ the wrong information being copied. Someone at Sun was complaining about
++ a bug in the handling of _COPY by SVr4, and this may in fact be what he
++ was talking about. Sigh. */
++
++/* No, there are cases where the SVr4 linker fails to emit COPY relocs
++ at all. */
++
++int
++_dl_parse_copy_information (struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ int i;
++ char *strtab;
++ int reloc_type;
++ int goof = 0;
++ Elf32_Sym *symtab;
++ 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 = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof (Elf32_Rela);
++
++ symtab = (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, NULL, copyrel);
++ if (!symbol_addr)
++ {
++ _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ goof++;
++ }
++ }
++ if (!goof)
++ _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
++ symtab[symtab_index].st_size);
++ }
++ return goof;
++}
+diff -urN uClibc/ldso-0.9.24/ldso/m68k/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/m68k/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/m68k/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/m68k/ld_syscalls.h 2002-03-19 04:43:32.000000000 -0600
+@@ -0,0 +1,174 @@
++/*
++ * This file contains the system call macros and syscall
++ * numbers used by the shared library loader.
++ */
++
++#define __NR_exit 1
++#define __NR_read 3
++#define __NR_write 4
++#define __NR_open 5
++#define __NR_close 6
++#define __NR_getuid 24
++#define __NR_geteuid 49
++#define __NR_getgid 47
++#define __NR_getegid 50
++#define __NR_readlink 85
++#define __NR_mmap 90
++#define __NR_munmap 91
++#define __NR_stat 106
++#define __NR_mprotect 125
++
++
++/* Here are the macros which define how this platform makes
++ * system calls. This particular variant does _not_ set
++ * errno (note how it is disabled in __syscall_return) since
++ * these will get called before the errno symbol is dynamicly
++ * linked. */
++
++
++#define __syscall_return(type, res) \
++do { \
++ if ((unsigned long)(res) >= (unsigned long)(-125)) { \
++ /* avoid using res which is declared to be in register d0; \
++ errno might expand to a function call and clobber it. */ \
++ /* int __err = -(res); \
++ errno = __err; */ \
++ res = -1; \
++ } \
++ return (type) (res); \
++} while (0)
++
++#define _syscall0(type, name) \
++type name(void) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name) \
++ : "cc", "%d0"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
++#define _syscall1(type, name, atype, a) \
++type name(atype a) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %2, %%d1\n\t" \
++ "movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name), \
++ "g" ((long)a) \
++ : "cc", "%d0", "%d1"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
++#define _syscall2(type, name, atype, a, btype, b) \
++type name(atype a, btype b) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %3, %%d2\n\t" \
++ "movel %2, %%d1\n\t" \
++ "movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name), \
++ "a" ((long)a), \
++ "g" ((long)b) \
++ : "cc", "%d0", "%d1", "%d2"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
++#define _syscall3(type, name, atype, a, btype, b, ctype, c) \
++type name(atype a, btype b, ctype c) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %4, %%d3\n\t" \
++ "movel %3, %%d2\n\t" \
++ "movel %2, %%d1\n\t" \
++ "movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name), \
++ "a" ((long)a), \
++ "a" ((long)b), \
++ "g" ((long)c) \
++ : "cc", "%d0", "%d1", "%d2", "%d3"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
++#define _syscall4(type, name, atype, a, btype, b, ctype, c, dtype, d) \
++type name(atype a, btype b, ctype c, dtype d) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %5, %%d4\n\t" \
++ "movel %4, %%d3\n\t" \
++ "movel %3, %%d2\n\t" \
++ "movel %2, %%d1\n\t" \
++ "movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name), \
++ "a" ((long)a), \
++ "a" ((long)b), \
++ "a" ((long)c), \
++ "g" ((long)d) \
++ : "cc", "%d0", "%d1", "%d2", "%d3", \
++ "%d4"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
++#define _syscall5(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e)\
++type name(atype a, btype b, ctype c, dtype d, etype e) \
++{ \
++ long __res; \
++ __asm__ __volatile__ ("movel %6, %%d5\n\t" \
++ "movel %5, %%d4\n\t" \
++ "movel %4, %%d3\n\t" \
++ "movel %3, %%d2\n\t" \
++ "movel %2, %%d1\n\t" \
++ "movel %1, %%d0\n\t" \
++ "trap #0\n\t" \
++ "movel %%d0, %0" \
++ : "=g" (__res) \
++ : "i" (__NR_##name), \
++ "a" ((long)a), \
++ "a" ((long)b), \
++ "a" ((long)c), \
++ "a" ((long)d), \
++ "g" ((long)e) \
++ : "cc", "%d0", "%d1", "%d2", "%d3", \
++ "%d4", "%d5"); \
++ if ((unsigned long)(__res) >= (unsigned long)(-125)) { \
++ /* errno = -__res; */ \
++ __res = -1; \
++ } \
++ return (type)__res; \
++}
++
+diff -urN uClibc/ldso-0.9.24/ldso/m68k/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/m68k/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/m68k/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/m68k/ld_sysdep.h 2002-05-28 16:33:34.000000000 -0500
+@@ -0,0 +1,88 @@
++
++/* 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)))
++
++/* Initialization sequence for a GOT. */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[2] = (int) _dl_linux_resolve; \
++ GOT_BASE[1] = (int) (MODULE); \
++}
++
++/* Here is a macro to perform a relocation. This is only used when
++ bootstrapping the dynamic loader. RELP is the relocation that we
++ are performing, REL is the pointer to the address we are
++ relocating. SYMBOL is the symbol involved in the relocation, and
++ LOAD is the load address. */
++#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
++ switch (ELF32_R_TYPE ((RELP)->r_info)) \
++ { \
++ case R_68K_8: \
++ *(char *) (REL) = (SYMBOL) + (RELP)->r_addend; \
++ break; \
++ case R_68K_16: \
++ *(short *) (REL) = (SYMBOL) + (RELP)->r_addend; \
++ break; \
++ case R_68K_32: \
++ *(REL) = (SYMBOL) + (RELP)->r_addend; \
++ break; \
++ case R_68K_PC8: \
++ *(char *) (REL) = ((SYMBOL) + (RELP)->r_addend \
++ - (unsigned int) (REL)); \
++ break; \
++ case R_68K_PC16: \
++ *(short *) (REL) = ((SYMBOL) + (RELP)->r_addend \
++ - (unsigned int) (REL)); \
++ break; \
++ case R_68K_PC32: \
++ *(REL) = ((SYMBOL) + (RELP)->r_addend \
++ - (unsigned int) (REL)); \
++ break; \
++ case R_68K_GLOB_DAT: \
++ case R_68K_JMP_SLOT: \
++ *(REL) = (SYMBOL); \
++ break; \
++ case R_68K_RELATIVE: /* Compatibility kludge */ \
++ *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
++ break; \
++ default: \
++ _dl_exit (1); \
++ }
++
++
++/* Transfer control to the user's application, once the dynamic loader
++ is done. */
++
++#define START() \
++ __asm__ volatile ("unlk %%a6\n\t" \
++ "jmp %0@" \
++ : : "a" (_dl_elf_main));
++
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_68K
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "m68k"
++
++struct elf_resolve;
++extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
++
++/* Define this because we do not want to call .udiv in the library.
++ Not needed for m68k. */
++#define do_rem(result, n, base) ((result) = (n) % (base))
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/m68k/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/m68k/resolve.S
+--- uClibc/ldso-0.9.24/ldso/m68k/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/m68k/resolve.S 2001-04-27 12:23:26.000000000 -0500
+@@ -0,0 +1,21 @@
++/*
++ * These are various helper routines that are needed to run an ELF image.
++ */
++
++.text
++.even
++
++.globl _dl_linux_resolve
++ .type _dl_linux_resolve,@function
++_dl_linux_resolve:
++ moveml %a0/%a1,%sp@-
++#ifdef __PIC__
++ bsrl _dl_linux_resolver@PLTPC
++#else
++ jbsr _dl_linux_resolver
++#endif
++ moveml %sp@+,%a0/%a1
++ addql #8,%sp
++ jmp @(%d0)
++.LFE2:
++ .size _dl_linux_resolve,.LFE2-_dl_linux_resolve
+diff -urN uClibc/ldso-0.9.24/ldso/mips/README uClibc.ldso.24/ldso-0.9.24/ldso/mips/README
+--- uClibc/ldso-0.9.24/ldso/mips/README 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/README 2002-07-25 16:15:59.000000000 -0500
+@@ -0,0 +1,52 @@
++Almost all of the code present in these source files was taken
++from GLIBC. In the descriptions below, all files mentioned are
++with respect to the top level GLIBC source directory accept for
++code taken from the Linux kernel.
++
++boot1_arch.h
++------------
++Contains code to fix up the stack pointer so that the dynamic
++linker can find argc, argv and Auxillary Vector Table (AVT).
++The code is taken from the function 'RTLD_START' in the file
++'sysdeps/mips/dl-machine.h'.
++
++elfinterp.c
++-----------
++Contains the runtime resolver code taken from the function
++'__dl_runtime_resolve' in 'sysdeps/mips/dl-machine.h'. Also
++contains the function to perform relocations for objects
++other than the linker itself. The code was taken from the
++function 'elf_machine_rel' in 'sysdeps/mips/dl-machine.h'.
++
++ld_syscalls.h
++-------------
++Used to contain all the macro functions for the system calls
++as well as the list of system calls supported. We now include
++<sys/syscall.h> but with the __set_errno macro defined empty
++so we can use the same file for the linker as well as userspace.
++Original code was taken from the Linux kernel source 2.4.17 and
++can be found in the file 'include/asm-mips/unistd.h'.
++
++ld_sysdep.h
++-----------
++Contains bootstrap code for the dynamic linker, magic numbers
++for detecting MIPS target types and some macros. The macro
++function 'PERFORM_BOOTSTRAP_GOT' is used to relocate the dynamic
++linker's GOT so that function calls can be made. The code is
++taken from the function 'ELF_MACHINE_BEFORE_RTLD_RELOC' in the
++file 'sysdeps/mips/dl-machine.h'. The other macro function
++'PERFORM_BOOTSTRAP_RELOC' is used to do the relocations for
++the dynamic loader. The code is taken from the function
++'elf_machine_rel' in the file 'sysdeps/mips/dl-machine.h'. The
++final macro function is 'INIT_GOT' which initializes the GOT
++for the application being dynamically linked and loaded. The
++code is taken from the functions 'elf_machine_runtime_setup'
++and 'elf_machine_got_rel' in 'sysdeps/mips/dl-machine.h'.
++
++resolve.S
++---------
++Contains the low-level assembly code for the dynamic runtime
++resolver. The code is taken from the assembly code function
++'_dl_runtime_resolve' in the file 'sysdeps/mips/dl-machine.h'.
++The code looks a bit different since we only need to pass the
++symbol index and the old GP register.
+diff -urN uClibc/ldso-0.9.24/ldso/mips/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/mips/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/mips/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/boot1_arch.h 2003-06-12 16:39:10.000000000 -0500
+@@ -0,0 +1,38 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture.
++ */
++
++asm("" \
++" .text\n" \
++" .globl _dl_boot\n" \
++"_dl_boot:\n" \
++" .set noreorder\n" \
++" bltzal $0, 0f\n" \
++" nop\n" \
++"0: .cpload $31\n" \
++" .set reorder\n" \
++" la $4, _DYNAMIC\n" \
++" sw $4, -0x7ff0($28)\n" \
++" move $4, $29\n" \
++" la $8, coff\n" \
++" .set noreorder\n" \
++" bltzal $0, coff\n" \
++" nop\n" \
++"coff: subu $8, $31, $8\n" \
++" .set reorder\n" \
++" la $25, _dl_boot2\n" \
++" addu $25, $8\n" \
++" jalr $25\n" \
++" lw $4, 0($29)\n" \
++" la $5, 4($29)\n" \
++" sll $6, $4, 2\n" \
++" addu $6, $6, $5\n" \
++" addu $6, $6, 4\n" \
++" la $7, _dl_elf_main\n" \
++" lw $25, 0($7)\n" \
++" jr $25\n" \
++);
++
++#define _dl_boot _dl_boot2
++#define LD_BOOT(X) static void __attribute__ ((unused)) _dl_boot (X)
+diff -urN uClibc/ldso-0.9.24/ldso/mips/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/mips/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/mips/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/elfinterp.c 2003-08-22 02:04:16.000000000 -0500
+@@ -0,0 +1,301 @@
++/* vi: set sw=4 ts=4: */
++/* mips/mipsel ELF shared library loader suppport
++ *
++ Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com)
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] =
++{
++ [0] "R_MIPS_NONE", "R_MIPS_16", "R_MIPS_32",
++ [3] "R_MIPS_REL32", "R_MIPS_26", "R_MIPS_HI16",
++ [6] "R_MIPS_LO16", "R_MIPS_GPREL16", "R_MIPS_LITERAL",
++ [9] "R_MIPS_GOT16", "R_MIPS_PC16", "R_MIPS_CALL16",
++ [12] "R_MIPS_GPREL32",
++ [16] "R_MIPS_SHIFT5", "R_MIPS_SHIFT6", "R_MIPS_64",
++ [19] "R_MIPS_GOT_DISP", "R_MIPS_GOT_PAGE", "R_MIPS_GOT_OFST",
++ [22] "R_MIPS_GOT_HI16", "R_MIPS_GOT_LO16", "R_MIPS_SUB",
++ [25] "R_MIPS_INSERT_A", "R_MIPS_INSERT_B", "R_MIPS_DELETE",
++ [28] "R_MIPS_HIGHER", "R_MIPS_HIGHEST", "R_MIPS_CALL_HI16",
++ [31] "R_MIPS_CALL_LO16", "R_MIPS_SCN_DISP", "R_MIPS_REL16",
++ [34] "R_MIPS_ADD_IMMEDIATE", "R_MIPS_PJUMP", "R_MIPS_RELGOT",
++ [37] "R_MIPS_JALR",
++};
++
++static const char *
++_dl_reltypes(int type)
++{
++ static char buf[22];
++ const char *str;
++
++ if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ {
++ str =_dl_simple_ltoa( buf, (unsigned long)(type));
++ }
++ return str;
++}
++
++static
++void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
++{
++ if(_dl_debug_symbols)
++ {
++ if(symtab_index){
++ _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
++{
++ if(_dl_debug_reloc)
++ {
++ int symtab_index;
++ const char *sym;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++ if(_dl_debug_symbols)
++ _dl_dprintf(_dl_debug_file, "\n\t");
++ else
++ _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend);
++#else
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset);
++#endif
++ }
++}
++#endif
++
++extern int _dl_linux_resolve(void);
++
++#define OFFSET_GP_GOT 0x7ff0
++
++unsigned long _dl_linux_resolver(unsigned long sym_index,
++ unsigned long old_gpreg)
++{
++ unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT);
++ struct elf_resolve *tpnt = (struct elf_resolve *) got[1];
++ Elf32_Sym *sym;
++ char *strtab;
++ unsigned long local_gotno;
++ unsigned long gotsym;
++ unsigned long new_addr;
++ unsigned long instr_addr;
++ char **got_addr;
++ char *symname;
++
++ gotsym = tpnt->mips_gotsym;
++ local_gotno = tpnt->mips_local_gotno;
++
++ sym = ((Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr)) + sym_index;
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ symname = strtab + sym->st_name;
++
++ new_addr = (unsigned long) _dl_find_hash(strtab + sym->st_name,
++ tpnt->symbol_scope, tpnt, resolver);
++
++ /* Address of jump instruction to fix up */
++ instr_addr = (unsigned long) (got + local_gotno + sym_index - gotsym);
++ got_addr = (char **) instr_addr;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
++ }
++ if (!_dl_debug_nofixups) {
++ *got_addr = (char*)new_addr;
++ }
++#else
++ *got_addr = (char*)new_addr;
++#endif
++
++ return new_addr;
++}
++
++void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ /* Nothing to do */
++ return;
++}
++
++int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ /* Nothing to do */
++ return 0;
++}
++
++
++int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ Elf32_Sym *symtab;
++ Elf32_Rel *rpnt;
++ char *strtab;
++ unsigned long *got;
++ unsigned long *reloc_addr=NULL, old_val=0;
++ unsigned long symbol_addr;
++ int i, reloc_type, symtab_index;
++
++ /* Now parse the relocation information */
++ rel_size = rel_size / sizeof(Elf32_Rel);
++ rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
++
++ symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ got = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
++
++ for (i = 0; i < rel_size; i++, rpnt++) {
++ reloc_addr = (unsigned long *) (tpnt->loadaddr +
++ (unsigned long) 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 defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,rpnt);
++ old_val = *reloc_addr;
++#endif
++
++ switch (reloc_type) {
++ case R_MIPS_REL32:
++ if (symtab_index) {
++ if (symtab_index < tpnt->mips_gotsym)
++ *reloc_addr +=
++ symtab[symtab_index].st_value +
++ (unsigned long) tpnt->loadaddr;
++ else {
++ *reloc_addr += got[symtab_index + tpnt->mips_local_gotno -
++ tpnt->mips_gotsym];
++ }
++ }
++ else {
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ }
++ break;
++ case R_MIPS_NONE:
++ break;
++ default:
++ {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ _dl_dprintf(2, "\n%s: ",_dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
++#endif
++ _dl_exit(1);
++ }
++ };
++
++ };
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
++{
++ Elf32_Sym *sym;
++ char *strtab;
++ unsigned long i;
++ unsigned long *got_entry;
++
++ for (; tpnt ; tpnt = tpnt->next) {
++
++ /* We don't touch the dynamic linker */
++ if (tpnt->libtype == program_interpreter)
++ continue;
++
++ /* Setup the loop variables */
++ got_entry = (unsigned long *) (tpnt->loadaddr +
++ tpnt->dynamic_info[DT_PLTGOT]) + tpnt->mips_local_gotno;
++ sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] +
++ (unsigned long) tpnt->loadaddr) + tpnt->mips_gotsym;
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] +
++ (unsigned long) tpnt->loadaddr);
++ i = tpnt->mips_symtabno - tpnt->mips_gotsym;
++
++ /* Relocate the global GOT entries for the object */
++ while(i--) {
++ if (sym->st_shndx == SHN_UNDEF) {
++ if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value)
++ *got_entry = sym->st_value + (unsigned long) tpnt->loadaddr;
++ else {
++ *got_entry = (unsigned long) _dl_find_hash(strtab +
++ sym->st_name, tpnt->symbol_scope, NULL, copyrel);
++ }
++ }
++ else if (sym->st_shndx == SHN_COMMON) {
++ *got_entry = (unsigned long) _dl_find_hash(strtab +
++ sym->st_name, tpnt->symbol_scope, NULL, copyrel);
++ }
++ else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
++ *got_entry != sym->st_value)
++ *got_entry += (unsigned long) tpnt->loadaddr;
++ else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {
++ if (sym->st_other == 0)
++ *got_entry += (unsigned long) tpnt->loadaddr;
++ }
++ else {
++ *got_entry = (unsigned long) _dl_find_hash(strtab +
++ sym->st_name, tpnt->symbol_scope, NULL, copyrel);
++ }
++
++ got_entry++;
++ sym++;
++ }
++ }
++}
+diff -urN uClibc/ldso-0.9.24/ldso/mips/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/mips/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/mips/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/ld_syscalls.h 2002-08-09 07:20:20.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Define the __set_errno macro as nothing so that we don't bother
++ * setting errno, which is important since we make system calls
++ * before the errno symbol is dynamicly linked. */
++
++#define __set_errno(X) {(void)(X);}
++#include "sys/syscall.h"
++
+diff -urN uClibc/ldso-0.9.24/ldso/mips/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/mips/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/mips/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/ld_sysdep.h 2002-05-28 16:33:36.000000000 -0500
+@@ -0,0 +1,136 @@
++/* vi: set sw=4 ts=4: */
++
++/*
++ * 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 long *) ARGS)
++
++
++/*
++ * Initialization sequence for the application/library GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++do { \
++ unsigned long i; \
++ \
++ /* Check if this is the dynamic linker itself */ \
++ if (MODULE->libtype == program_interpreter) \
++ continue; \
++ \
++ /* Fill in first two GOT entries according to the ABI */ \
++ GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \
++ GOT_BASE[1] = (unsigned long) MODULE; \
++ \
++ /* Add load address displacement to all local GOT entries */ \
++ i = 2; \
++ while (i < MODULE->mips_local_gotno) \
++ GOT_BASE[i++] += (unsigned long) MODULE->loadaddr; \
++ \
++} while (0)
++
++
++/*
++ * Here is a macro to perform the GOT relocation. This is only
++ * used when bootstrapping the dynamic loader.
++ */
++#define PERFORM_BOOTSTRAP_GOT(got) \
++do { \
++ Elf32_Sym *sym; \
++ unsigned long i; \
++ \
++ /* Add load address displacement to all local GOT entries */ \
++ i = 2; \
++ while (i < tpnt->mips_local_gotno) \
++ got[i++] += load_addr; \
++ \
++ /* Handle global GOT entries */ \
++ got += tpnt->mips_local_gotno; \
++ sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \
++ load_addr) + tpnt->mips_gotsym; \
++ i = tpnt->mips_symtabno - tpnt->mips_gotsym; \
++ \
++ while (i--) { \
++ if (sym->st_shndx == SHN_UNDEF || \
++ sym->st_shndx == SHN_COMMON) \
++ *got = load_addr + sym->st_value; \
++ else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \
++ *got != sym->st_value) \
++ *got += load_addr; \
++ else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \
++ if (sym->st_other == 0) \
++ *got += load_addr; \
++ } \
++ else \
++ *got = load_addr + sym->st_value; \
++ \
++ got++; \
++ sym++; \
++ } \
++} while (0)
++
++
++/*
++ * 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_MIPS_REL32: \
++ if (symtab_index) { \
++ if (symtab_index < tpnt->mips_gotsym) \
++ *REL += SYMBOL; \
++ } \
++ else { \
++ *REL += LOAD; \
++ } \
++ break; \
++ case R_MIPS_NONE: \
++ break; \
++ default: \
++ SEND_STDERR("Aiieeee!"); \
++ _dl_exit(1); \
++ }
++
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. This routine has to exit the current function, then
++ * call the _dl_elf_main function. For MIPS, we do it in assembly
++ * because the stack doesn't get properly restored otherwise. Got look
++ * at boot1_arch.h
++ */
++#define START()
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++#define MAGIC1 EM_MIPS
++#define MAGIC2 EM_MIPS_RS3_LE
++
++
++/* Used for error messages */
++#define ELF_TARGET "MIPS"
++
++
++unsigned long _dl_linux_resolver(unsigned long sym_index,
++ unsigned long old_gpreg);
++
++
++#define do_rem(result, n, base) result = (n % base)
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/mips/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/mips/resolve.S
+--- uClibc/ldso-0.9.24/ldso/mips/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/mips/resolve.S 2003-01-30 10:40:26.000000000 -0600
+@@ -0,0 +1,45 @@
++ /*
++ * Linux dynamic resolving code for MIPS. Fixes up the GOT entry as
++ * indicated in register t8 and jumps to the resolved address. Shamelessly
++ * ripped from 'sysdeps/mips/dl-machine.h' in glibc-2.2.5.
++ *
++ * This file is subject to the terms and conditions of the GNU Lesser General
++ * Public License. See the file "COPYING.LIB" in the main directory of this
++ * archive for more details.
++ *
++ * Copyright (C) 1996-2001 Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>
++ * Copyright (C) 2002 Steven J. Hill <sjhill@realitydiluted.com>
++ *
++ */
++.text
++.align 2
++.globl _dl_linux_resolve
++.type _dl_linux_resolve,@function
++.ent _dl_linux_resolve
++_dl_linux_resolve:
++ .frame $29, 40, $31
++ .set noreorder
++ move $3, $28 # Save GP
++ addu $25, 8 # t9 ($25) now points at .cpload instruction
++ .cpload $25 # Compute GP
++ .set reorder
++ subu $29, 40
++ .cprestore 32
++ sw $15, 36($29)
++ sw $4, 16($29)
++ sw $5, 20($29)
++ sw $6, 24($29)
++ sw $7, 28($29)
++ move $4, $24
++ move $5, $3
++ jal _dl_linux_resolver
++ lw $31, 36($29)
++ lw $4, 16($29)
++ lw $5, 20($29)
++ lw $6, 24($29)
++ lw $7, 28($29)
++ addu $29, 40
++ move $25, $2
++ jr $25
++.size _dl_linux_resolve,.-_dl_linux_resolve
++.end _dl_linux_resolve
+diff -urN uClibc/ldso-0.9.24/ldso/powerpc/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/powerpc/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/boot1_arch.h 2003-02-15 19:22:41.000000000 -0600
+@@ -0,0 +1,20 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. */
++
++/* Overrive the default _dl_boot function, and replace it with a bit of asm.
++ * Then call the real _dl_boot function, which is now named _dl_boot2. */
++
++asm("" \
++" .text\n" \
++" .globl _dl_boot\n" \
++"_dl_boot:\n" \
++" mr 3,1\n" \
++" addi 1,1,-16\n" \
++" bl _dl_boot2\n" \
++".previous\n" \
++);
++
++#define _dl_boot _dl_boot2
++#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X)
++
+diff -urN uClibc/ldso-0.9.24/ldso/powerpc/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/powerpc/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/elfinterp.c 2003-12-03 17:28:33.000000000 -0600
+@@ -0,0 +1,621 @@
++/* vi: set sw=4 ts=4: */
++/* powerpc shared library loader suppport
++ *
++ * Copyright (C) 2001-2002, David A. Schleef
++ * Copyright (C) 2003, Erik Andersen
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] =
++ { "R_PPC_NONE", "R_PPC_ADDR32", "R_PPC_ADDR24", "R_PPC_ADDR16",
++ "R_PPC_ADDR16_LO", "R_PPC_ADDR16_HI", "R_PPC_ADDR16_HA",
++ "R_PPC_ADDR14", "R_PPC_ADDR14_BRTAKEN", "R_PPC_ADDR14_BRNTAKEN",
++ "R_PPC_REL24", "R_PPC_REL14", "R_PPC_REL14_BRTAKEN",
++ "R_PPC_REL14_BRNTAKEN", "R_PPC_GOT16", "R_PPC_GOT16_LO",
++ "R_PPC_GOT16_HI", "R_PPC_GOT16_HA", "R_PPC_PLTREL24",
++ "R_PPC_COPY", "R_PPC_GLOB_DAT", "R_PPC_JMP_SLOT", "R_PPC_RELATIVE",
++ "R_PPC_LOCAL24PC", "R_PPC_UADDR32", "R_PPC_UADDR16", "R_PPC_REL32",
++ "R_PPC_PLT32", "R_PPC_PLTREL32", "R_PPC_PLT16_LO", "R_PPC_PLT16_HI",
++ "R_PPC_PLT16_HA", "R_PPC_SDAREL16", "R_PPC_SECTOFF",
++ "R_PPC_SECTOFF_LO", "R_PPC_SECTOFF_HI", "R_PPC_SECTOFF_HA",
++};
++
++static const char *
++_dl_reltypes(int type)
++{
++ static char buf[22];
++ const char *str;
++
++ if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ {
++ str =_dl_simple_ltoa( buf, (unsigned long)(type));
++ }
++ return str;
++}
++
++static
++void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
++{
++ if(_dl_debug_symbols)
++ {
++ if(symtab_index){
++ _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static
++void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
++{
++ if(_dl_debug_reloc)
++ {
++ int symtab_index;
++ const char *sym;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++ if(_dl_debug_symbols)
++ _dl_dprintf(_dl_debug_file, "\n\t");
++ else
++ _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend);
++#else
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset);
++#endif
++ }
++}
++#endif
++
++extern int _dl_linux_resolve(void);
++
++void _dl_init_got(unsigned long *plt,struct elf_resolve *tpnt)
++{
++ unsigned long target_addr = (unsigned long)_dl_linux_resolve;
++ unsigned int n_plt_entries;
++ unsigned long *tramp;
++ unsigned long data_words;
++ unsigned int rel_offset_words;
++
++ //DPRINTF("init_got plt=%x, tpnt=%x\n", (unsigned long)plt,(unsigned long)tpnt);
++
++ n_plt_entries = tpnt->dynamic_info[DT_PLTRELSZ] / sizeof(ELF_RELOC);
++ //DPRINTF("n_plt_entries %d\n",n_plt_entries);
++
++ rel_offset_words = PLT_DATA_START_WORDS(n_plt_entries);
++ //DPRINTF("rel_offset_words %x\n",rel_offset_words);
++ data_words = (unsigned long)(plt + rel_offset_words);
++ //DPRINTF("data_words %x\n",data_words);
++
++ tpnt->data_words = data_words;
++
++ plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI(11, 11, data_words);
++ plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = OPCODE_LWZ(11,data_words,11);
++
++ plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR(11);
++ plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR();
++
++ /* [4] */
++ /* [5] */
++
++ tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
++ tramp[0] = OPCODE_ADDIS_HI(11,11,-data_words);
++ tramp[1] = OPCODE_ADDI(11,11,-data_words);
++ tramp[2] = OPCODE_SLWI(12,11,1);
++ tramp[3] = OPCODE_ADD(11,12,11);
++ tramp[4] = OPCODE_LI(12,target_addr);
++ tramp[5] = OPCODE_ADDIS_HI(12,12,target_addr);
++ tramp[6] = OPCODE_MTCTR(12);
++ tramp[7] = OPCODE_LI(12,(unsigned long)tpnt);
++ tramp[8] = OPCODE_ADDIS_HI(12,12,(unsigned long)tpnt);
++ tramp[9] = OPCODE_BCTR();
++
++ /* [16] unused */
++ /* [17] unused */
++
++ /* instructions were modified */
++ PPC_DCBST(plt);
++ PPC_DCBST(plt+4);
++ PPC_DCBST(plt+8);
++ PPC_DCBST(plt+12);
++ PPC_DCBST(plt+16-1);
++ PPC_SYNC;
++ PPC_ICBI(plt);
++ PPC_ICBI(plt+4); /* glibc thinks this is not needed */
++ PPC_ICBI(plt+8); /* glibc thinks this is not needed */
++ PPC_ICBI(plt+12); /* glibc thinks this is not needed */
++ PPC_ICBI(plt+16-1);
++ PPC_ISYNC;
++}
++
++unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ ELF_RELOC *this_reloc;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rel_addr;
++ int symtab_index;
++ char *symname;
++ unsigned long insn_addr;
++ unsigned long *insns;
++ unsigned long new_addr;
++ unsigned long delta;
++
++ rel_addr = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
++
++ this_reloc = (void *)rel_addr + reloc_entry;
++ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
++ symtab_index = ELF32_R_SYM(this_reloc->r_info);
++
++ symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ symname = strtab + symtab[symtab_index].st_name;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,this_reloc);
++#endif
++
++ if (reloc_type != R_PPC_JMP_SLOT) {
++ _dl_dprintf(2, "%s: Incorrect relocation type in jump relocation\n", _dl_progname);
++ _dl_exit(1);
++ };
++
++ /* Address of dump instruction to fix up */
++ insn_addr = (unsigned long) tpnt->loadaddr +
++ (unsigned long) this_reloc->r_offset;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\n\tResolving symbol %s %x --> ", symname, insn_addr);
++#endif
++
++ /* Get the address of the GOT entry */
++ new_addr = (unsigned long) _dl_find_hash(
++ strtab + symtab[symtab_index].st_name,
++ tpnt->symbol_scope, tpnt, resolver);
++ if (!new_addr) {
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, symname);
++ _dl_exit(1);
++ };
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "%x\n", new_addr);
++#endif
++
++ insns = (unsigned long *)insn_addr;
++ delta = new_addr - insn_addr;
++
++ if(delta<<6>>6 == delta){
++ insns[0] = OPCODE_B(delta);
++ }else if (new_addr <= 0x01fffffc || new_addr >= 0xfe000000){
++ insns[0] = OPCODE_BA (new_addr);
++ }else{
++ /* Warning: we don't handle double-sized PLT entries */
++ unsigned long plt_addr;
++ unsigned long *ptr;
++ int index;
++
++ plt_addr = (unsigned long)tpnt->dynamic_info[DT_PLTGOT] +
++ (unsigned long)tpnt->loadaddr;
++
++ delta = PLT_LONGBRANCH_ENTRY_WORDS*4 - (insn_addr-plt_addr+4);
++
++ index = (insn_addr - plt_addr - PLT_INITIAL_ENTRY_WORDS*4)/8;
++
++ ptr = (unsigned long *)tpnt->data_words;
++ //DPRINTF("plt_addr=%x delta=%x index=%x ptr=%x\n", plt_addr, delta, index, ptr);
++ insns += 1;
++
++ ptr[index] = new_addr;
++ PPC_SYNC;
++ /* icache sync is not necessary, since this will be a data load */
++ //PPC_DCBST(ptr+index);
++ //PPC_SYNC;
++ //PPC_ICBI(ptr+index);
++ //PPC_ISYNC;
++
++ insns[0] = OPCODE_B(delta);
++
++ }
++
++ /* instructions were modified */
++ PPC_DCBST(insns);
++ PPC_SYNC;
++ PPC_ICBI(insns);
++ PPC_ISYNC;
++
++ return new_addr;
++}
++
++static int
++_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
++ unsigned long rel_addr, unsigned long rel_size,
++ int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
++{
++ unsigned int i;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rpnt;
++ int symtab_index;
++
++ /* Now parse the relocation information */
++ rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof(ELF_RELOC);
++
++ symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++ for (i = 0; i < rel_size; i++, rpnt++) {
++ int res;
++
++ 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;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,rpnt);
++#endif
++
++ res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
++
++ if (res==0) continue;
++
++ _dl_dprintf(2, "\n%s: ",_dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++ if (res <0)
++ {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
++#endif
++ _dl_exit(-res);
++ }
++ else if (res >0)
++ {
++ _dl_dprintf(2, "can't resolve symbol\n");
++ return res;
++ }
++ }
++ return 0;
++}
++
++static int
++_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ unsigned long reloc_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++ (void)scope;
++ (void)symtab;
++ (void)strtab;
++
++ reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long) rpnt->r_offset;
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = reloc_addr;
++#endif
++
++ switch (reloc_type) {
++ case R_PPC_NONE:
++ return 0;
++ break;
++ case R_PPC_JMP_SLOT:
++ {
++ int index;
++ unsigned long delta;
++ unsigned long *plt;
++ unsigned long *insns;
++
++ plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
++
++ delta = (unsigned long)(plt+PLT_TRAMPOLINE_ENTRY_WORDS+2) - (reloc_addr+4);
++
++ index = (reloc_addr - (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
++ /sizeof(unsigned long);
++ index /= 2;
++ //DPRINTF(" index %x delta %x\n",index,delta);
++ insns = (unsigned long *)reloc_addr;
++ insns[0] = OPCODE_LI(11,index*4);
++ insns[1] = OPCODE_B(delta);
++ break;
++ }
++ default:
++#if 0
++ _dl_dprintf(2, "%s: (LAZY) can't handle reloc type ",
++ _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if (symtab_index)
++ _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
++#endif
++ //_dl_exit(1);
++ return -1;
++ };
++
++ /* instructions were modified */
++ PPC_DCBST(reloc_addr);
++ PPC_DCBST(reloc_addr+4);
++ PPC_SYNC;
++ PPC_ICBI(reloc_addr);
++ PPC_ICBI(reloc_addr+4);
++ PPC_ISYNC;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x", old_val, reloc_addr);
++#endif
++ return 0;
++
++}
++
++static int
++_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ char *symname;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
++ (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel);
++
++ /*
++ * 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) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
++ symname, tpnt->libname);
++#endif
++ return 0;
++ }
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_PPC_NONE:
++ return 0;
++ break;
++ case R_PPC_REL24:
++#if 0
++ {
++ unsigned long delta = symbol_addr - (unsigned long)reloc_addr;
++ if(delta<<6>>6 != delta){
++ _dl_dprintf(2,"R_PPC_REL24: Reloc out of range\n");
++ _dl_exit(1);
++ }
++ *reloc_addr &= 0xfc000003;
++ *reloc_addr |= delta&0x03fffffc;
++ }
++ break;
++#else
++ _dl_dprintf(2, "%s: symbol '%s' is type R_PPC_REL24\n\tCompile shared libraries with -fPIC!\n",
++ _dl_progname, symname);
++ _dl_exit(1);
++#endif
++ case R_PPC_RELATIVE:
++ *reloc_addr = (unsigned long)tpnt->loadaddr + (unsigned long)rpnt->r_addend;
++ break;
++ case R_PPC_ADDR32:
++ *reloc_addr += symbol_addr;
++ break;
++ case R_PPC_ADDR16_HA:
++ /* XXX is this correct? */
++ *(short *)reloc_addr += (symbol_addr+0x8000)>>16;
++ break;
++ case R_PPC_ADDR16_HI:
++ *(short *)reloc_addr += symbol_addr>>16;
++ break;
++ case R_PPC_ADDR16_LO:
++ *(short *)reloc_addr += symbol_addr;
++ break;
++ case R_PPC_JMP_SLOT:
++ {
++ unsigned long targ_addr = (unsigned long)*reloc_addr;
++ unsigned long delta = targ_addr - (unsigned long)reloc_addr;
++ if(delta<<6>>6 == delta){
++ *reloc_addr = OPCODE_B(delta);
++ }else if (targ_addr <= 0x01fffffc || targ_addr >= 0xfe000000){
++ *reloc_addr = OPCODE_BA (targ_addr);
++ }else{
++ {
++ int index;
++ unsigned long delta2;
++ unsigned long *plt, *ptr;
++ plt = (unsigned long *)(tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
++
++ delta2 = (unsigned long)(plt+PLT_LONGBRANCH_ENTRY_WORDS)
++ - (unsigned long)(reloc_addr+1);
++
++ index = ((unsigned long)reloc_addr -
++ (unsigned long)(plt+PLT_INITIAL_ENTRY_WORDS))
++ /sizeof(unsigned long);
++ index /= 2;
++ //DPRINTF(" index %x delta %x\n",index,delta2);
++ ptr = (unsigned long *)tpnt->data_words;
++ ptr[index] = targ_addr;
++ reloc_addr[0] = OPCODE_LI(11,index*4);
++ reloc_addr[1] = OPCODE_B(delta2);
++
++ /* instructions were modified */
++ PPC_DCBST(reloc_addr+1);
++ PPC_SYNC;
++ PPC_ICBI(reloc_addr+1);
++ }
++ }
++ break;
++ }
++ case R_PPC_GLOB_DAT:
++ *reloc_addr += symbol_addr;
++ break;
++ case R_PPC_COPY:
++ // handled later
++ return 0;
++ break;
++ default:
++#if 0
++ _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if (symtab_index)
++ _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
++#endif
++ //_dl_exit(1);
++ return -1;
++ };
++
++ /* instructions were modified */
++ PPC_DCBST(reloc_addr);
++ PPC_SYNC;
++ PPC_ICBI(reloc_addr);
++ PPC_ISYNC;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++
++/* 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. */
++static int
++_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int goof = 0;
++ char *symname;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ if (reloc_type != R_PPC_COPY)
++ return 0;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
++ if (!symbol_addr) goof++;
++ }
++ if (!goof) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_move)
++ _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
++ symname, symtab[symtab_index].st_size,
++ symbol_addr, symtab[symtab_index].st_value);
++#endif
++ _dl_memcpy((char *) reloc_addr,
++ (char *) symbol_addr, symtab[symtab_index].st_size);
++ }
++
++ return goof;
++}
++
++void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
++}
++
++int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
++}
++
++int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
++}
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/powerpc/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/powerpc/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/ld_syscalls.h 2003-06-14 20:08:43.000000000 -0500
+@@ -0,0 +1,244 @@
++/*
++ * This file contains the system call macros and syscall
++ * numbers used by the shared library loader.
++ */
++
++#define __NR_exit 1
++#define __NR_read 3
++#define __NR_write 4
++#define __NR_open 5
++#define __NR_close 6
++#define __NR_getpid 20
++#define __NR_getuid 24
++#define __NR_geteuid 49
++#define __NR_getgid 47
++#define __NR_getegid 50
++#define __NR_readlink 85
++#define __NR_mmap 90
++#define __NR_munmap 91
++#define __NR_stat 106
++#define __NR_mprotect 125
++
++/* Here are the macros which define how this platform makes
++ * system calls. This particular variant does _not_ set
++ * errno (note how it is disabled in __syscall_return) since
++ * these will get called before the errno symbol is dynamicly
++ * linked. */
++
++#undef __syscall_return
++#define __syscall_return(type) \
++ return (__sc_err & 0x10000000 ? /*errno = __sc_ret,*/ __sc_ret = -1 : 0), \
++ (type) __sc_ret
++
++#undef __syscall_clobbers
++#define __syscall_clobbers \
++ "r9", "r10", "r11", "r12"
++ //"r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
++
++#undef _syscall0
++#define _syscall0(type,name) \
++type name(void) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0) \
++ : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++#undef _syscall1
++#define _syscall1(type,name,type1,arg1) \
++type name(type1 arg1) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0) \
++ : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++#undef _syscall2
++#define _syscall2(type,name,type1,arg1,type2,arg2) \
++type name(type1 arg1, type2 arg2) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ register unsigned long __sc_4 __asm__ ("r4"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_4 = (unsigned long) (arg2); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0), \
++ "r" (__sc_4) \
++ : "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++#undef _syscall3
++#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
++type name(type1 arg1, type2 arg2, type3 arg3) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ register unsigned long __sc_4 __asm__ ("r4"); \
++ register unsigned long __sc_5 __asm__ ("r5"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_4 = (unsigned long) (arg2); \
++ __sc_5 = (unsigned long) (arg3); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0), \
++ "r" (__sc_4), \
++ "r" (__sc_5) \
++ : "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++#undef _syscall4
++#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
++type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ register unsigned long __sc_4 __asm__ ("r4"); \
++ register unsigned long __sc_5 __asm__ ("r5"); \
++ register unsigned long __sc_6 __asm__ ("r6"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_4 = (unsigned long) (arg2); \
++ __sc_5 = (unsigned long) (arg3); \
++ __sc_6 = (unsigned long) (arg4); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0), \
++ "r" (__sc_4), \
++ "r" (__sc_5), \
++ "r" (__sc_6) \
++ : "r7", "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++#undef _syscall5
++#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
++type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ register unsigned long __sc_4 __asm__ ("r4"); \
++ register unsigned long __sc_5 __asm__ ("r5"); \
++ register unsigned long __sc_6 __asm__ ("r6"); \
++ register unsigned long __sc_7 __asm__ ("r7"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_4 = (unsigned long) (arg2); \
++ __sc_5 = (unsigned long) (arg3); \
++ __sc_6 = (unsigned long) (arg4); \
++ __sc_7 = (unsigned long) (arg5); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0), \
++ "r" (__sc_4), \
++ "r" (__sc_5), \
++ "r" (__sc_6), \
++ "r" (__sc_7) \
++ : "r8", "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++
++#undef _syscall6
++#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
++type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
++{ \
++ unsigned long __sc_ret, __sc_err; \
++ { \
++ register unsigned long __sc_0 __asm__ ("r0"); \
++ register unsigned long __sc_3 __asm__ ("r3"); \
++ register unsigned long __sc_4 __asm__ ("r4"); \
++ register unsigned long __sc_5 __asm__ ("r5"); \
++ register unsigned long __sc_6 __asm__ ("r6"); \
++ register unsigned long __sc_7 __asm__ ("r7"); \
++ register unsigned long __sc_8 __asm__ ("r8"); \
++ \
++ __sc_3 = (unsigned long) (arg1); \
++ __sc_4 = (unsigned long) (arg2); \
++ __sc_5 = (unsigned long) (arg3); \
++ __sc_6 = (unsigned long) (arg4); \
++ __sc_7 = (unsigned long) (arg5); \
++ __sc_8 = (unsigned long) (arg6); \
++ __sc_0 = __NR_##name; \
++ __asm__ __volatile__ \
++ ("sc \n\t" \
++ "mfcr %1 " \
++ : "=&r" (__sc_3), "=&r" (__sc_0) \
++ : "0" (__sc_3), "1" (__sc_0), \
++ "r" (__sc_4), \
++ "r" (__sc_5), \
++ "r" (__sc_6), \
++ "r" (__sc_7), \
++ "r" (__sc_8) \
++ : "r9", "r10", "r11", "r12" ); \
++ __sc_ret = __sc_3; \
++ __sc_err = __sc_0; \
++ } \
++ __syscall_return (type); \
++}
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/powerpc/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/powerpc/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/ld_sysdep.h 2003-12-03 17:38:43.000000000 -0600
+@@ -0,0 +1,136 @@
++/*
++ * 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 long*) ARGS)+1)
++
++/*
++ * Initialization sequence for a GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) _dl_init_got(GOT_BASE,MODULE)
++
++/* Stuff for the PLT. */
++#define PLT_INITIAL_ENTRY_WORDS 18
++#define PLT_LONGBRANCH_ENTRY_WORDS 0
++#define PLT_TRAMPOLINE_ENTRY_WORDS 6
++#define PLT_DOUBLE_SIZE (1<<13)
++#define PLT_ENTRY_START_WORDS(entry_number) \
++ (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2 \
++ + ((entry_number) > PLT_DOUBLE_SIZE \
++ ? ((entry_number) - PLT_DOUBLE_SIZE)*2 \
++ : 0))
++#define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
++
++/* Macros to build PowerPC opcode words. */
++#define OPCODE_ADDI(rd,ra,simm) \
++ (0x38000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
++#define OPCODE_ADDIS(rd,ra,simm) \
++ (0x3c000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
++#define OPCODE_ADD(rd,ra,rb) \
++ (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
++#define OPCODE_B(target) (0x48000000 | ((target) & 0x03fffffc))
++#define OPCODE_BA(target) (0x48000002 | ((target) & 0x03fffffc))
++#define OPCODE_BCTR() 0x4e800420
++#define OPCODE_LWZ(rd,d,ra) \
++ (0x80000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
++#define OPCODE_LWZU(rd,d,ra) \
++ (0x84000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
++#define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
++#define OPCODE_RLWINM(ra,rs,sh,mb,me) \
++ (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
++
++#define OPCODE_LI(rd,simm) OPCODE_ADDI(rd,0,simm)
++#define OPCODE_ADDIS_HI(rd,ra,value) \
++ OPCODE_ADDIS(rd,ra,((value) + 0x8000) >> 16)
++#define OPCODE_LIS_HI(rd,value) OPCODE_ADDIS_HI(rd,0,value)
++#define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
++
++
++#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
++#define PPC_SYNC asm volatile ("sync" : : : "memory")
++#define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
++#define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
++#define PPC_DIE asm volatile ("tweq 0,0")
++
++/*
++ * 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.
++ */
++// finaladdr = LOAD ?
++#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
++ {int type=ELF32_R_TYPE((RELP)->r_info); \
++ if(type==R_PPC_NONE){ \
++ }else if(type==R_PPC_ADDR32){ \
++ *REL += (SYMBOL); \
++ }else if(type==R_PPC_RELATIVE){ \
++ *REL = (Elf32_Word)(LOAD) + (RELP)->r_addend; \
++ }else if(type==R_PPC_REL24){ \
++ Elf32_Sword delta = (Elf32_Word)(SYMBOL) - (Elf32_Word)(REL); \
++ *REL &= 0xfc000003; \
++ *REL |= (delta & 0x03fffffc); \
++ }else if(type==R_PPC_JMP_SLOT){ \
++ Elf32_Sword delta = (Elf32_Word)(SYMBOL) - (Elf32_Word)(REL); \
++ /*if (delta << 6 >> 6 != delta)_dl_exit(99);*/ \
++ *REL = OPCODE_B(delta); \
++ }else{ \
++ _dl_exit(100+ELF32_R_TYPE((RELP)->r_info)); \
++ } \
++ if(type!=R_PPC_NONE){ \
++ PPC_DCBST(REL); PPC_SYNC; PPC_ICBI(REL);\
++ } \
++ }
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. This routine has to exit the current function, then
++ * call the _dl_elf_main function.
++ */
++
++/* hgb@ifi.uio.no:
++ * Adding a clobber list consisting of r0 for %1. addi on PowerPC
++ * takes a register as the second argument, but if the register is
++ * r0, the value 0 is used instead. If r0 is used here, the stack
++ * pointer (r1) will be zeroed, and the dynamically linked
++ * application will seg.fault immediatly when receiving control.
++ */
++#define START() \
++ __asm__ volatile ( \
++ "addi 1,%1,0\n\t" \
++ "mtlr %0\n\t" \
++ "blrl\n\t" \
++ : : "r" (_dl_elf_main), "r" (args) \
++ : "r0")
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_PPC
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "powerpc"
++
++struct elf_resolve;
++extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
++void _dl_init_got(unsigned long *lpnt,struct elf_resolve *tpnt);
++
++
++#define do_rem(result, n, base) result = (n % base)
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/powerpc/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/resolve.S
+--- uClibc/ldso-0.9.24/ldso/powerpc/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/powerpc/resolve.S 2001-07-12 05:14:09.000000000 -0500
+@@ -0,0 +1,82 @@
++/*
++ * Stolen from glibc-2.2.2 by David Schleef <ds@schleef.org>
++ */
++
++.text
++.align 4
++
++.globl _dl_linux_resolver
++
++.globl _dl_linux_resolve
++.type _dl_linux_resolve,@function
++
++_dl_linux_resolve:
++// We need to save the registers used to pass parameters, and register 0,
++// which is used by _mcount; the registers are saved in a stack frame.
++ stwu 1,-64(1)
++ stw 0,12(1)
++ stw 3,16(1)
++ stw 4,20(1)
++// The code that calls this has put parameters for 'fixup' in r12 and r11.
++ mr 3,12
++ stw 5,24(1)
++ mr 4,11
++ stw 6,28(1)
++ mflr 0
++// We also need to save some of the condition register fields.
++ stw 7,32(1)
++ stw 0,48(1)
++ stw 8,36(1)
++ mfcr 0
++ stw 9,40(1)
++ stw 10,44(1)
++ stw 0,8(1)
++ bl _dl_linux_resolver@local
++// 'fixup' returns the address we want to branch to.
++ mtctr 3
++// Put the registers back...
++ lwz 0,48(1)
++ lwz 10,44(1)
++ lwz 9,40(1)
++ mtlr 0
++ lwz 8,36(1)
++ lwz 0,8(1)
++ lwz 7,32(1)
++ lwz 6,28(1)
++ mtcrf 0xFF,0
++ lwz 5,24(1)
++ lwz 4,20(1)
++ lwz 3,16(1)
++ lwz 0,12(1)
++// ...unwind the stack frame, and jump to the PLT entry we updated.
++ addi 1,1,64
++ bctr
++
++.LFE2:
++ .size _dl_linux_resolve,.LFE2-_dl_linux_resolve
++
++#if 0
++
++ pusha /* preserve all regs */
++ lea 0x20(%esp),%eax /* eax = tpnt and reloc_entry params */
++ pushl 4(%eax) /* push copy of reloc_entry param */
++ pushl (%eax) /* push copy of tpnt param */
++
++#ifdef __PIC__
++ call .L24
++.L24:
++ popl %ebx
++ addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
++ movl _dl_linux_resolver@GOT(%ebx),%ebx /* eax = resolved func */
++ call *%ebx
++#else
++ call _dl_linux_resolver
++#endif
++ movl %eax,0x28(%esp) /* store func addr over original
++ * tpnt param */
++ addl $0x8,%esp /* remove copy parameters */
++ popa /* restore regs */
++ ret $4 /* jump to func removing original
++ * reloc_entry param from stack */
++#endif
++
+diff -urN uClibc/ldso-0.9.24/ldso/readelflib1.c uClibc.ldso.24/ldso-0.9.24/ldso/readelflib1.c
+--- uClibc/ldso-0.9.24/ldso/readelflib1.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/readelflib1.c 2003-12-05 14:24:26.000000000 -0600
+@@ -0,0 +1,971 @@
++/* vi: set sw=4 ts=4: */
++/* Program to load an ELF binary on a linux system, and run it
++ * after resolving ELF shared library symbols
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ * Copyright (C) 2001-2003, Erik Andersen
++ *
++ * 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.
++ */
++
++
++/* This file contains the helper routines to load an ELF sharable
++ library into memory and add the symbol table info to the chain. */
++
++#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;
++ libentry_t *libent;
++ int i, strtabsize;
++
++ if (_dl_cache_addr == (caddr_t) - 1)
++ return -1;
++ else if (_dl_cache_addr != NULL)
++ return 0;
++
++ if (_dl_stat(LDSO_CACHE, &st)
++ || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) {
++ _dl_dprintf(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_mmap_check_error(_dl_cache_addr)) {
++ _dl_dprintf(2, "%s: can't map cache '%s'\n",
++ _dl_progname, LDSO_CACHE);
++ return -1;
++ }
++
++ header = (header_t *) _dl_cache_addr;
++
++ if (_dl_cache_size < sizeof(header_t) ||
++ _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)
++ || _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)
++ || _dl_cache_size <
++ (sizeof(header_t) + header->nlibs * sizeof(libentry_t))
++ || _dl_cache_addr[_dl_cache_size - 1] != '\0')
++ {
++ _dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname,
++ LDSO_CACHE);
++ goto fail;
++ }
++
++ strtabsize = _dl_cache_size - sizeof(header_t) -
++ header->nlibs * sizeof(libentry_t);
++ libent = (libentry_t *) & header[1];
++
++ for (i = 0; i < header->nlibs; i++) {
++ if (libent[i].sooffset >= strtabsize ||
++ libent[i].liboffset >= strtabsize)
++ {
++ _dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
++ goto fail;
++ }
++ }
++
++ return 0;
++
++ fail:
++ _dl_munmap(_dl_cache_addr, _dl_cache_size);
++ _dl_cache_addr = (caddr_t) - 1;
++ return -1;
++}
++
++int _dl_unmap_cache(void)
++{
++ if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t) - 1)
++ return -1;
++
++#if 1
++ _dl_munmap(_dl_cache_addr, _dl_cache_size);
++ _dl_cache_addr = NULL;
++#endif
++
++ return 0;
++}
++
++#endif
++
++/* This function's behavior must exactly match that
++ * in uClibc/ldso/util/ldd.c */
++static struct elf_resolve *
++search_for_named_library(const char *name, int secure, const char *path_list,
++ struct dyn_elf **rpnt)
++{
++ int i, count = 1;
++ char *path, *path_n;
++ char mylibname[2050];
++ struct elf_resolve *tpnt1;
++
++ if (path_list==NULL)
++ return NULL;
++
++ /* We need a writable copy of this string */
++ path = _dl_strdup(path_list);
++ if (!path) {
++ _dl_dprintf(2, "Out of memory!\n");
++ _dl_exit(0);
++ }
++
++
++ /* Unlike ldd.c, don't bother to eliminate double //s */
++
++
++ /* Replace colons with zeros in path_list and count them */
++ for(i=_dl_strlen(path); i > 0; i--) {
++ if (path[i]==':') {
++ path[i]=0;
++ count++;
++ }
++ }
++
++ path_n = path;
++ for (i = 0; i < count; i++) {
++ _dl_strcpy(mylibname, path_n);
++ _dl_strcat(mylibname, "/");
++ _dl_strcat(mylibname, name);
++ if ((tpnt1 = _dl_load_elf_shared_library(secure, rpnt, mylibname)) != NULL)
++ {
++ return tpnt1;
++ }
++ path_n += (_dl_strlen(path_n) + 1);
++ }
++ return NULL;
++}
++
++/* Check if the named library is already loaded... */
++struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname)
++{
++ const char *pnt, *pnt1;
++ struct elf_resolve *tpnt1;
++ const char *libname, *libname2;
++ static const char *libc = "libc.so.";
++ static const char *aborted_wrong_lib = "%s: aborted attempt to load %s!\n";
++
++ pnt = libname = full_libname;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Checking if '%s' is already loaded\n", full_libname);
++#endif
++ /* quick hack to ensure mylibname buffer doesn't overflow. don't
++ allow full_libname or any directory to be longer than 1024. */
++ if (_dl_strlen(full_libname) > 1024)
++ return NULL;
++
++ /* Skip over any initial initial './' and '/' stuff to
++ * get the short form libname with no path garbage */
++ pnt1 = _dl_strrchr(pnt, '/');
++ if (pnt1) {
++ libname = pnt1 + 1;
++ }
++
++ /* Make sure they are not trying to load the wrong C library!
++ * This sometimes happens esp with shared libraries when the
++ * library path is somehow wrong! */
++#define isdigit(c) (c >= '0' && c <= '9')
++ if ((_dl_strncmp(libname, libc, 8) == 0) && _dl_strlen(libname) >=8 &&
++ isdigit(libname[8]))
++ {
++ /* Abort attempts to load glibc, libc5, etc */
++ if ( libname[8]!='0') {
++ if (!_dl_trace_loaded_objects) {
++ _dl_dprintf(2, aborted_wrong_lib, libname, _dl_progname);
++ _dl_exit(1);
++ }
++ return NULL;
++ }
++ }
++
++ /* Critical step! Weed out duplicates early to avoid
++ * function aliasing, which wastes memory, and causes
++ * really bad things to happen with weaks and globals. */
++ for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
++
++ /* Skip over any initial initial './' and '/' stuff to
++ * get the short form libname with no path garbage */
++ libname2 = tpnt1->libname;
++ pnt1 = _dl_strrchr(libname2, '/');
++ if (pnt1) {
++ libname2 = pnt1 + 1;
++ }
++
++ if (_dl_strcmp(libname2, libname) == 0) {
++ /* Well, that was certainly easy */
++ return tpnt1;
++ }
++ }
++
++ return NULL;
++}
++
++
++
++/*
++ * Used to return error codes back to dlopen et. al.
++ */
++
++unsigned long _dl_error_number;
++unsigned long _dl_internal_error_number;
++extern char *_dl_ldsopath;
++
++struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
++ struct elf_resolve *tpnt, char *full_libname)
++{
++ char *pnt, *pnt1;
++ struct elf_resolve *tpnt1;
++ char *libname;
++
++ _dl_internal_error_number = 0;
++ libname = full_libname;
++
++ /* quick hack to ensure mylibname buffer doesn't overflow. don't
++ allow full_libname or any directory to be longer than 1024. */
++ if (_dl_strlen(full_libname) > 1024)
++ goto goof;
++
++ /* Skip over any initial initial './' and '/' stuff to
++ * get the short form libname with no path garbage */
++ pnt1 = _dl_strrchr(libname, '/');
++ if (pnt1) {
++ libname = pnt1 + 1;
++ }
++
++ /* Critical step! Weed out duplicates early to avoid
++ * function aliasing, which wastes memory, and causes
++ * really bad things to happen with weaks and globals. */
++ if ((tpnt1=_dl_check_if_named_library_is_loaded(libname))!=NULL)
++ return tpnt1;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfind library='%s'; searching\n", libname);
++#endif
++ /* If the filename has any '/', try it straight and leave it at that.
++ For IBCS2 compatibility under linux, we substitute the string
++ /usr/i486-sysv4/lib for /usr/lib in library names. */
++
++ if (libname != full_libname) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\ttrying file='%s'\n", full_libname);
++#endif
++ tpnt1 = _dl_load_elf_shared_library(secure, rpnt, full_libname);
++ if (tpnt1) {
++ return tpnt1;
++ }
++ //goto goof;
++ }
++
++ /*
++ * The ABI specifies that RPATH is searched before LD_*_PATH or
++ * the default path of /usr/lib. Check in rpath directories.
++ */
++ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
++ if (tpnt->libtype == elf_executable) {
++ pnt = (char *) tpnt->dynamic_info[DT_RPATH];
++ if (pnt) {
++ pnt += (unsigned long) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching RPATH='%s'\n", pnt);
++#endif
++ if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL)
++ {
++ return tpnt1;
++ }
++ }
++ }
++ }
++
++ /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
++ if (_dl_library_path) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching LD_LIBRARY_PATH='%s'\n", _dl_library_path);
++#endif
++ if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL)
++ {
++ return tpnt1;
++ }
++ }
++
++ /*
++ * Where should the cache be searched? There is no such concept in the
++ * ABI, so we have some flexibility here. For now, search it before
++ * the hard coded paths that follow (i.e before /lib and /usr/lib).
++ */
++#ifdef USE_CACHE
++ if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t) - 1) {
++ int i;
++ header_t *header = (header_t *) _dl_cache_addr;
++ libentry_t *libent = (libentry_t *) & header[1];
++ char *strs = (char *) &libent[header->nlibs];
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching cache='%s'\n", LDSO_CACHE);
++#endif
++ for (i = 0; i < header->nlibs; i++) {
++ if ((libent[i].flags == LIB_ELF ||
++ libent[i].flags == LIB_ELF_LIBC5) &&
++ _dl_strcmp(libname, strs + libent[i].sooffset) == 0 &&
++ (tpnt1 = _dl_load_elf_shared_library(secure,
++ rpnt, strs + libent[i].liboffset)))
++ return tpnt1;
++ }
++ }
++#endif
++
++ /* Look for libraries wherever the shared library loader
++ * was installed */
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching ldso dir='%s'\n", _dl_ldsopath);
++#endif
++ if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL)
++ {
++ return tpnt1;
++ }
++
++
++ /* Lastly, search the standard list of paths for the library.
++ This list must exactly match the list in uClibc/ldso/util/ldd.c */
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching full lib path list\n");
++#endif
++ if ((tpnt1 = search_for_named_library(libname, secure,
++ UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib:"
++ UCLIBC_RUNTIME_PREFIX "usr/lib:"
++ UCLIBC_RUNTIME_PREFIX "lib:"
++ "/usr/lib:"
++ "/lib", rpnt)
++ ) != NULL)
++ {
++ 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 = LD_ERROR_NOFILE;
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(2, "Bummer: could not find '%s'!\n", libname);
++#endif
++ 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(int secure,
++ struct dyn_elf **rpnt, char *libname)
++{
++ ElfW(Ehdr) *epnt;
++ unsigned long dynamic_addr = 0;
++ unsigned long dynamic_size = 0;
++ Elf32_Dyn *dpnt;
++ struct elf_resolve *tpnt;
++ ElfW(Phdr) *ppnt;
++ char *status, *header;
++ unsigned long dynamic_info[24];
++ unsigned long *lpnt;
++ unsigned long libaddr;
++ unsigned long minvma = 0xffffffff, maxvma = 0;
++ int i, flags, piclib, infile;
++
++ /* If this file is already loaded, skip this step */
++ tpnt = _dl_check_hashed_files(libname);
++ if (tpnt) {
++ if (*rpnt) {
++ (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
++ _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
++ (*rpnt)->next->prev = (*rpnt);
++ *rpnt = (*rpnt)->next;
++ (*rpnt)->dyn = tpnt;
++ tpnt->symbol_scope = _dl_symbol_tables;
++ }
++ tpnt->usage_count++;
++ tpnt->libtype = elf_lib;
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(2, "file='%s'; already loaded\n", libname);
++#endif
++ return tpnt;
++ }
++
++ /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
++ we don't load the library if it isn't setuid. */
++
++ if (secure) {
++ struct stat st;
++
++ if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
++ return NULL;
++ }
++
++ libaddr = 0;
++ infile = _dl_open(libname, O_RDONLY);
++ if (infile < 0) {
++#if 0
++ /*
++ * NO! When we open shared libraries we may search several paths.
++ * it is inappropriate to generate an error here.
++ */
++ _dl_dprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
++#endif
++ _dl_internal_error_number = LD_ERROR_NOFILE;
++ return NULL;
++ }
++
++ header = _dl_mmap((void *) 0, 4096, PROT_READ | PROT_WRITE,
++ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
++ if (_dl_mmap_check_error(header)) {
++ _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
++ _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
++ _dl_close(infile);
++ return NULL;
++ };
++
++ _dl_read(infile, header, 4096);
++ epnt = (ElfW(Ehdr) *) (intptr_t) header;
++ if (epnt->e_ident[0] != 0x7f ||
++ epnt->e_ident[1] != 'E' ||
++ epnt->e_ident[2] != 'L' ||
++ epnt->e_ident[3] != 'F')
++ {
++ _dl_dprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname,
++ libname);
++ _dl_internal_error_number = LD_ERROR_NOTELF;
++ _dl_close(infile);
++ _dl_munmap(header, 4096);
++ 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 ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC);
++ _dl_dprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET
++ "\n", _dl_progname, libname);
++ _dl_close(infile);
++ _dl_munmap(header, 4096);
++ return NULL;
++ };
++
++ ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
++
++ piclib = 1;
++ for (i = 0; i < epnt->e_phnum; i++) {
++
++ if (ppnt->p_type == PT_DYNAMIC) {
++ if (dynamic_addr)
++ _dl_dprintf(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 long) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
++ maxvma = ppnt->p_vaddr + ppnt->p_memsz;
++ }
++ }
++ ppnt++;
++ };
++
++ maxvma = (maxvma + ADDR_ALIGN) & ~ADDR_ALIGN;
++ minvma = minvma & ~0xffffU;
++
++ flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ;
++ if (!piclib)
++ flags |= MAP_FIXED;
++
++ status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma),
++ maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0);
++ if (_dl_mmap_check_error(status)) {
++ _dl_dprintf(2, "%s: can't map %s\n", _dl_progname, libname);
++ _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
++ _dl_close(infile);
++ _dl_munmap(header, 4096);
++ return NULL;
++ };
++ libaddr = (unsigned long) status;
++ flags |= MAP_FIXED;
++
++ /* Get the memory to store the library */
++ ppnt = (ElfW(Phdr) *)(intptr_t) & 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 long map_size;
++ char *cpnt;
++
++ status = (char *) _dl_mmap((char *) ((piclib ? libaddr : 0) +
++ (ppnt->p_vaddr & PAGE_ALIGN)), (ppnt->p_vaddr & ADDR_ALIGN)
++ + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile,
++ ppnt->p_offset & OFFS_ALIGN);
++
++ if (_dl_mmap_check_error(status)) {
++ _dl_dprintf(2, "%s: can't map '%s'\n",
++ _dl_progname, libname);
++ _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
++ _dl_munmap((char *) libaddr, maxvma - minvma);
++ _dl_close(infile);
++ _dl_munmap(header, 4096);
++ return NULL;
++ };
++
++ /* Pad the last page with zeroes. */
++ cpnt = (char *) (status + (ppnt->p_vaddr & ADDR_ALIGN) +
++ ppnt->p_filesz);
++ while (((unsigned long) cpnt) & ADDR_ALIGN)
++ *cpnt++ = 0;
++
++ /* I am not quite sure if this is completely
++ * correct to do or not, but the basic way that
++ * we handle bss segments is that we mmap
++ * /dev/zero if there are any pages left over
++ * that are not mapped as part of the file */
++
++ map_size = (ppnt->p_vaddr + ppnt->p_filesz + ADDR_ALIGN) & PAGE_ALIGN;
++
++ if (map_size < ppnt->p_vaddr + ppnt->p_memsz)
++ status = (char *) _dl_mmap((char *) map_size +
++ (piclib ? libaddr : 0),
++ ppnt->p_vaddr + ppnt->p_memsz - map_size,
++ LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS, -1, 0);
++ } else
++ status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & PAGE_ALIGN)
++ + (piclib ? libaddr : 0), (ppnt->p_vaddr & ADDR_ALIGN) +
++ ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags,
++ infile, ppnt->p_offset & OFFS_ALIGN);
++ if (_dl_mmap_check_error(status)) {
++ _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
++ _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
++ _dl_munmap((char *) libaddr, maxvma - minvma);
++ _dl_close(infile);
++ _dl_munmap(header, 4096);
++ return NULL;
++ };
++
++ /* if(libaddr == 0 && piclib) {
++ libaddr = (unsigned long) status;
++ flags |= MAP_FIXED;
++ }; */
++ };
++ ppnt++;
++ };
++ _dl_close(infile);
++
++ /* For a non-PIC library, the addresses are all absolute */
++ if (piclib) {
++ dynamic_addr += (unsigned long) 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 = LD_ERROR_NODYNAMIC;
++ _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n",
++ _dl_progname, libname);
++ _dl_munmap(header, 4096);
++ return NULL;
++ }
++
++ dpnt = (Elf32_Dyn *) dynamic_addr;
++
++ dynamic_size = dynamic_size / sizeof(Elf32_Dyn);
++ _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
++
++#if defined(__mips__)
++ {
++
++ int indx = 1;
++ Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr;
++
++ while(dpnt->d_tag) {
++ dpnt++;
++ indx++;
++ }
++ dynamic_size = indx;
++ }
++#endif
++
++ {
++ unsigned long indx;
++
++ for (indx = 0; indx < dynamic_size; indx++)
++ {
++ if (dpnt->d_tag > DT_JMPREL) {
++ dpnt++;
++ continue;
++ }
++ dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
++ if (dpnt->d_tag == DT_TEXTREL)
++ dynamic_info[DT_TEXTREL] = 1;
++ dpnt++;
++ };
++ }
++
++ /* If the TEXTREL is set, this means that we need to make the pages
++ writable before we perform relocations. Do this now. They get set
++ back again later. */
++
++ if (dynamic_info[DT_TEXTREL]) {
++#ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
++ ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
++ for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
++ if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
++ _dl_mprotect((void *) ((piclib ? libaddr : 0) +
++ (ppnt->p_vaddr & PAGE_ALIGN)),
++ (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
++ PROT_READ | PROT_WRITE | PROT_EXEC);
++ }
++#else
++ _dl_dprintf(_dl_debug_file, "Can't modify %s's text section. Use GCC option -fPIC for shared objects, please.\n",libname);
++ _dl_exit(1);
++#endif
++ }
++
++ tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info,
++ dynamic_addr, dynamic_size);
++
++ tpnt->ppnt = (ElfW(Phdr) *)(intptr_t) (tpnt->loadaddr + epnt->e_phoff);
++ tpnt->n_phent = epnt->e_phnum;
++
++ /*
++ * Add this object into the symbol chain
++ */
++ if (*rpnt) {
++ (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
++ _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
++ (*rpnt)->next->prev = (*rpnt);
++ *rpnt = (*rpnt)->next;
++ (*rpnt)->dyn = tpnt;
++ tpnt->symbol_scope = _dl_symbol_tables;
++ }
++ tpnt->usage_count++;
++ tpnt->libtype = elf_lib;
++
++ /*
++ * 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 = (unsigned long *) dynamic_info[DT_PLTGOT];
++
++ if (lpnt) {
++ lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] +
++ ((int) libaddr));
++ INIT_GOT(lpnt, tpnt);
++ };
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) {
++ _dl_dprintf(2, "\n\tfile='%s'; generating link map\n", libname);
++ _dl_dprintf(2, "\t\tdynamic: %x base: %x size: %x\n",
++ dynamic_addr, libaddr, dynamic_size);
++ _dl_dprintf(2, "\t\t entry: %x phdr: %x phnum: %d\n\n",
++ epnt->e_entry + libaddr, tpnt->ppnt, tpnt->n_phent);
++
++ }
++#endif
++ _dl_munmap(header, 4096);
++
++ return tpnt;
++}
++
++/* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY
++ relocations for global variables that are present both in the image and
++ the shared library. Go through and do it manually. If the images
++ are guaranteed to be generated by a trustworthy linker, then this
++ step can be skipped. */
++
++int _dl_copy_fixups(struct dyn_elf *rpnt)
++{
++ int goof = 0;
++ struct elf_resolve *tpnt;
++
++ if (rpnt->next)
++ goof += _dl_copy_fixups(rpnt->next);
++ else
++ return 0;
++
++ tpnt = rpnt->dyn;
++
++ if (tpnt->init_flag & COPY_RELOCS_DONE)
++ return goof;
++ tpnt->init_flag |= COPY_RELOCS_DONE;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s", tpnt->libname);
++#endif
++
++#ifdef ELF_USES_RELOCA
++ goof += _dl_parse_copy_information(rpnt,
++ tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0);
++
++#else
++ goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
++ tpnt->dynamic_info[DT_RELSZ], 0);
++
++#endif
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s; finished\n\n", tpnt->libname);
++#endif
++ return goof;
++}
++
++/* Minimal printf which handles only %s, %d, and %x */
++void _dl_dprintf(int fd, const char *fmt, ...)
++{
++ int num;
++ va_list args;
++ char *start, *ptr, *string;
++ static char *buf;
++
++ buf = _dl_mmap((void *) 0, 4096, PROT_READ | PROT_WRITE,
++ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
++ if (_dl_mmap_check_error(buf)) {
++ _dl_dprintf(2, "%s: mmap of a spare page failed!\n", _dl_progname);
++ _dl_exit(20);
++ }
++
++ start = ptr = buf;
++
++ if (!fmt)
++ return;
++
++ if (_dl_strlen(fmt) >= (sizeof(buf) - 1))
++ _dl_write(fd, "(overflow)\n", 10);
++
++ _dl_strcpy(buf, fmt);
++ va_start(args, fmt);
++
++ while (start) {
++ while (*ptr != '%' && *ptr) {
++ ptr++;
++ }
++
++ if (*ptr == '%') {
++ *ptr++ = '\0';
++ _dl_write(fd, start, _dl_strlen(start));
++
++ switch (*ptr++) {
++ case 's':
++ string = va_arg(args, char *);
++
++ if (!string)
++ _dl_write(fd, "(null)", 6);
++ else
++ _dl_write(fd, string, _dl_strlen(string));
++ break;
++
++ case 'i':
++ case 'd':
++ {
++ char tmp[22];
++ num = va_arg(args, int);
++
++ string = _dl_simple_ltoa(tmp, num);
++ _dl_write(fd, string, _dl_strlen(string));
++ break;
++ }
++ case 'x':
++ case 'X':
++ {
++ char tmp[22];
++ num = va_arg(args, int);
++
++ string = _dl_simple_ltoahex(tmp, num);
++ _dl_write(fd, string, _dl_strlen(string));
++ break;
++ }
++ default:
++ _dl_write(fd, "(null)", 6);
++ break;
++ }
++
++ start = ptr;
++ } else {
++ _dl_write(fd, start, _dl_strlen(start));
++ start = NULL;
++ }
++ }
++ _dl_munmap(buf, 4096);
++ return;
++}
++
++char *_dl_strdup(const char *string)
++{
++ char *retval;
++ int len;
++
++ len = _dl_strlen(string);
++ retval = _dl_malloc(len + 1);
++ _dl_strcpy(retval, string);
++ return retval;
++}
++
++void *(*_dl_malloc_function) (size_t size) = NULL;
++void *_dl_malloc(int size)
++{
++ void *retval;
++
++#if 0
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(2, "malloc: request for %d bytes\n", size);
++#endif
++#endif
++
++ if (_dl_malloc_function)
++ return (*_dl_malloc_function) (size);
++
++ if (_dl_malloc_addr - _dl_mmap_zero + size > 4096) {
++#ifdef __SUPPORT_LD_DEBUG_EARLY__
++ _dl_dprintf(2, "malloc: mmapping more memory\n");
++#endif
++ _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, size,
++ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
++ if (_dl_mmap_check_error(_dl_mmap_zero)) {
++ _dl_dprintf(2, "%s: mmap of a spare page failed!\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 long) _dl_malloc_addr + 3) & ~(3));
++ return retval;
++}
++
++int _dl_fixup(struct elf_resolve *tpnt, int flag)
++{
++ int goof = 0;
++
++ if (tpnt->next)
++ goof += _dl_fixup(tpnt->next, flag);
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
++#endif
++
++ if (tpnt->dynamic_info[DT_REL]) {
++#ifdef ELF_USES_RELOCA
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
++#endif
++ goof++;
++ return goof;
++#else
++ if (tpnt->init_flag & RELOCS_DONE)
++ return goof;
++ tpnt->init_flag |= RELOCS_DONE;
++ goof += _dl_parse_relocation_information(tpnt,
++ tpnt->dynamic_info[DT_REL],
++ tpnt->dynamic_info[DT_RELSZ], 0);
++#endif
++ }
++ if (tpnt->dynamic_info[DT_RELA]) {
++#ifndef ELF_USES_RELOCA
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) _dl_dprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
++#endif
++ goof++;
++ return goof;
++#else
++ if (tpnt->init_flag & RELOCS_DONE)
++ return goof;
++ tpnt->init_flag |= RELOCS_DONE;
++ goof += _dl_parse_relocation_information(tpnt,
++ tpnt->dynamic_info[DT_RELA],
++ tpnt->dynamic_info[DT_RELASZ], 0);
++#endif
++ }
++ if (tpnt->dynamic_info[DT_JMPREL]) {
++ if (tpnt->init_flag & JMP_RELOCS_DONE)
++ return goof;
++ tpnt->init_flag |= JMP_RELOCS_DONE;
++ if (flag & RTLD_LAZY) {
++ _dl_parse_lazy_relocation_information(tpnt,
++ tpnt->dynamic_info[DT_JMPREL],
++ tpnt->dynamic_info [DT_PLTRELSZ], 0);
++ } else {
++ goof += _dl_parse_relocation_information(tpnt,
++ tpnt->dynamic_info[DT_JMPREL],
++ tpnt->dynamic_info[DT_PLTRELSZ], 0);
++ }
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug) {
++ _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
++ _dl_dprintf(_dl_debug_file,"; finished\n\n");
++ }
++#endif
++ return goof;
++}
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/sh/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/sh/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/sh/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sh/boot1_arch.h 2002-11-03 08:12:29.000000000 -0600
+@@ -0,0 +1,22 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. */
++
++asm("" \
++" .text\n" \
++" .globl _dl_boot\n" \
++"_dl_boot:\n" \
++" mov r15, r4\n" \
++" mov.l .L_dl_boot2, r0\n" \
++" bsrf r0\n" \
++" add #4, r4\n" \
++".jmp_loc:\n" \
++" jmp @r0\n" \
++" mov #0, r4 !call _start with arg == 0\n" \
++".L_dl_boot2:\n" \
++" .long _dl_boot2-.jmp_loc\n" \
++" .previous\n" \
++);
++
++#define _dl_boot _dl_boot2
++#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X)
+diff -urN uClibc/ldso-0.9.24/ldso/sh/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/sh/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/sh/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sh/elfinterp.c 2003-09-11 05:26:16.000000000 -0500
+@@ -0,0 +1,427 @@
++/* vi: set sw=4 ts=4: */
++/* SuperH ELF shared library loader suppport
++ *
++ * Copyright (C) 2002, Stefan Allius <allius@atecom.com> and
++ * Eddie C. Dost <ecd@atecom.com>
++ *
++ * 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.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const char *_dl_reltypes_tab[] =
++{
++ [0] "R_SH_NONE", "R_SH_DIR32", "R_SH_REL32", "R_SH_DIR8WPN",
++ [4] "R_SH_IND12W", "R_SH_DIR8WPL", "R_SH_DIR8WPZ", "R_SH_DIR8BP",
++ [8] "R_SH_DIR8W", "R_SH_DIR8L",
++ [25] "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES",
++ [28] "R_SH_COUNT", "R_SH_ALIGN", "R_SH_CODE", "R_SH_DATA",
++ [32] "R_SH_LABEL", "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY",
++[160] "R_SH_GOT32", "R_SH_PLT32", "R_SH_COPY", "R_SH_GLOB_DAT",
++[164] "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF", "R_SH_GOTPC",
++};
++
++static const char *
++_dl_reltypes(int type)
++{
++ static char buf[22];
++ const char *str;
++
++ if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
++ NULL == (str = _dl_reltypes_tab[type]))
++ {
++ str =_dl_simple_ltoa( buf, (unsigned long)(type));
++ }
++ return str;
++}
++
++static
++void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
++{
++ if(_dl_debug_symbols)
++ {
++ if(symtab_index){
++ _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
++ strtab + symtab[symtab_index].st_name,
++ symtab[symtab_index].st_value,
++ symtab[symtab_index].st_size,
++ symtab[symtab_index].st_info,
++ symtab[symtab_index].st_other,
++ symtab[symtab_index].st_shndx);
++ }
++ }
++}
++
++static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
++{
++ if(_dl_debug_reloc)
++ {
++ int symtab_index;
++ const char *sym;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
++
++ if(_dl_debug_symbols)
++ _dl_dprintf(_dl_debug_file, "\n\t");
++ else
++ _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
++
++#ifdef ELF_USES_RELOCA
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset,
++ rpnt->r_addend);
++#else
++ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
++ _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
++ rpnt->r_offset);
++#endif
++ }
++}
++#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. */
++
++extern int _dl_linux_resolve(void);
++
++unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
++{
++ int reloc_type;
++ ELF_RELOC *this_reloc;
++ char *strtab;
++ Elf32_Sym *symtab;
++ int symtab_index;
++ char *rel_addr;
++ char *new_addr;
++ char **got_addr;
++ unsigned long instr_addr;
++ char *symname;
++
++ rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
++
++ this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
++ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
++ symtab_index = ELF32_R_SYM(this_reloc->r_info);
++
++ symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (reloc_type != R_SH_JMP_SLOT) {
++ _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
++ _dl_progname);
++ _dl_exit(1);
++ }
++
++ /* Address of jump instruction to fix up */
++ instr_addr = ((unsigned long) this_reloc->r_offset +
++ (unsigned long) tpnt->loadaddr);
++ got_addr = (char **) instr_addr;
++
++
++ /* Get the address of the GOT entry */
++ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
++ if (!new_addr) {
++ new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
++ if (new_addr) {
++ return (unsigned long) new_addr;
++ }
++
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
++ _dl_exit(1);
++ }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if ((unsigned long) got_addr < 0x20000000)
++ {
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
++ }
++ }
++ if (!_dl_debug_nofixups) {
++ *got_addr = new_addr;
++ }
++#else
++ *got_addr = new_addr;
++#endif
++
++ return (unsigned long) new_addr;
++}
++
++
++static int
++_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
++ unsigned long rel_addr, unsigned long rel_size,
++ int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
++{
++ unsigned int i;
++ char *strtab;
++ Elf32_Sym *symtab;
++ ELF_RELOC *rpnt;
++ int symtab_index;
++ /* Now parse the relocation information */
++
++ rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr);
++ rel_size = rel_size / sizeof(ELF_RELOC);
++
++ symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++ for (i = 0; i < rel_size; i++, rpnt++) {
++ int res;
++
++ 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;
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ debug_sym(symtab,strtab,symtab_index);
++ debug_reloc(symtab,strtab,rpnt);
++#endif
++
++ res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
++
++ if (res==0) continue;
++
++ _dl_dprintf(2, "\n%s: ",_dl_progname);
++
++ if (symtab_index)
++ _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
++
++ if (res <0)
++ {
++ int reloc_type = ELF32_R_TYPE(rpnt->r_info);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
++#else
++ _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
++#endif
++ _dl_exit(-res);
++ }
++ else if (res >0)
++ {
++ _dl_dprintf(2, "can't resolve symbol\n");
++ return res;
++ }
++ }
++ return 0;
++}
++
++
++static int
++_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ char *symname;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++
++
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
++ (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL), symbolrel);
++
++ /*
++ * 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) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
++ symname, tpnt->libname);
++#endif
++ return 0;
++ }
++ }
++
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_SH_NONE:
++ break;
++ case R_SH_COPY:
++ /* handled later on */
++ break;
++ case R_SH_DIR32:
++ case R_SH_GLOB_DAT:
++ case R_SH_JMP_SLOT:
++ *reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_SH_REL32:
++ *reloc_addr = symbol_addr + rpnt->r_addend -
++ (unsigned long) reloc_addr;
++ break;
++ case R_SH_RELATIVE:
++ *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++
++ return 0;
++}
++
++
++static int
++_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ unsigned long *reloc_addr;
++#if defined (__SUPPORT_LD_DEBUG__)
++ unsigned long old_val;
++#endif
++ (void)scope;
++ (void)symtab;
++ (void)strtab;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ old_val = *reloc_addr;
++#endif
++ switch (reloc_type) {
++ case R_SH_NONE:
++ break;
++ case R_SH_JMP_SLOT:
++ *reloc_addr += (unsigned long) tpnt->loadaddr;
++ break;
++ default:
++ return -1; /*call _dl_exit(1) */
++ }
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_reloc && _dl_debug_detail)
++ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
++#endif
++ return 0;
++
++}
++
++/* 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 */
++static int
++_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope,
++ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
++{
++ int reloc_type;
++ int symtab_index;
++ unsigned long *reloc_addr;
++ unsigned long symbol_addr;
++ int goof = 0;
++ char*symname;
++
++ reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
++ reloc_type = ELF32_R_TYPE(rpnt->r_info);
++ if (reloc_type != R_SH_COPY)
++ return 0;
++ symtab_index = ELF32_R_SYM(rpnt->r_info);
++ symbol_addr = 0;
++ symname = strtab + symtab[symtab_index].st_name;
++
++ if (symtab_index) {
++
++ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
++ if (!symbol_addr) goof++;
++ }
++ if (!goof) {
++#if defined (__SUPPORT_LD_DEBUG__)
++ if(_dl_debug_move)
++ _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
++ symname, symtab[symtab_index].st_size,
++ symbol_addr, symtab[symtab_index].st_value);
++#endif
++ _dl_memcpy((char *) symtab[symtab_index].st_value,
++ (char *) symbol_addr, symtab[symtab_index].st_size);
++ }
++
++ return goof;
++}
++
++
++void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
++}
++
++int _dl_parse_relocation_information(struct elf_resolve *tpnt,
++ unsigned long rel_addr, unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
++}
++
++int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
++ unsigned long rel_size, int type)
++{
++ (void) type;
++ return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy);
++}
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/sh/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/sh/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/sh/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sh/ld_syscalls.h 2002-08-09 07:20:19.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Define the __set_errno macro as nothing so that we don't bother
++ * setting errno, which is important since we make system calls
++ * before the errno symbol is dynamicly linked. */
++
++#define __set_errno(X) {(void)(X);}
++#include "sys/syscall.h"
++
+diff -urN uClibc/ldso-0.9.24/ldso/sh/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/sh/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/sh/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sh/ld_sysdep.h 2002-11-07 20:18:16.000000000 -0600
+@@ -0,0 +1,144 @@
++/*
++ * 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 long*) ARGS)
++
++/*
++ * Initialization sequence for a GOT.
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
++ GOT_BASE[1] = (unsigned long) (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_SH_REL32: \
++ *(REL) = (SYMBOL) + (RELP)->r_addend \
++ - (unsigned long)(REL); \
++ break; \
++ case R_SH_DIR32: \
++ case R_SH_GLOB_DAT: \
++ case R_SH_JMP_SLOT: \
++ *(REL) = (SYMBOL) + (RELP)->r_addend; \
++ break; \
++ case R_SH_RELATIVE: \
++ *(REL) = (LOAD) + (RELP)->r_addend; \
++ break; \
++ case R_SH_NONE: \
++ break; \
++ default: \
++ SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type "); \
++ SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1); \
++ SEND_STDERR("REL, SYMBOL, LOAD: "); \
++ SEND_ADDRESS_STDERR(REL, 0); \
++ SEND_STDERR(", "); \
++ SEND_ADDRESS_STDERR(SYMBOL, 0); \
++ SEND_STDERR(", "); \
++ SEND_ADDRESS_STDERR(LOAD, 1); \
++ _dl_exit(1); \
++ }
++
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. This routine has to exit the current function, then
++ * call the _dl_elf_main function.
++ */
++
++#define START() return _dl_elf_main;
++
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_SH
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "sh"
++
++struct elf_resolve;
++extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
++
++static __inline__ unsigned int
++_dl_urem(unsigned int n, unsigned int base)
++{
++ int res;
++
++ __asm__ (""\
++ "mov #0, r0\n\t" \
++ "div0u\n\t" \
++ "" \
++ "! get one bit from the msb of the numerator into the T\n\t" \
++ "! bit and divide it by whats in %2. Put the answer bit\n\t" \
++ "! into the T bit so it can come out again at the bottom\n\t" \
++ "" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1 ; div1 %2, r0\n\t" \
++ "rotcl %1\n\t"
++ : "=r" (res)
++ : "0" (n), "r" (base)
++ : "r0","cc");
++
++ return n - (base * res);
++}
++
++#define do_rem(result, n, base) ((result) = _dl_urem((n), (base)))
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/sh/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/sh/resolve.S
+--- uClibc/ldso-0.9.24/ldso/sh/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sh/resolve.S 2002-11-07 20:18:16.000000000 -0600
+@@ -0,0 +1,91 @@
++/*
++ * Stolen from glibc-2.2.2 by Eddie C. Dost <ecd@atecom.com>
++ */
++
++ .text
++ .globl _dl_linux_resolver
++ .globl _dl_linux_resolve
++ .type _dl_linux_resolve, @function
++ .balign 16
++_dl_linux_resolve:
++ mov.l r3, @-r15
++ mov.l r4, @-r15
++ mov.l r5, @-r15
++ mov.l r6, @-r15
++ mov.l r7, @-r15
++ mov.l r12, @-r15
++ movt r3 ! Save T flag
++ mov.l r3, @-r15
++
++#ifdef HAVE_FPU
++ sts.l fpscr, @-r15
++ mov #8,r3
++ swap.w r3, r3
++ lds r3, fpscr
++ fmov.s fr11, @-r15
++ fmov.s fr10, @-r15
++ fmov.s fr9, @-r15
++ fmov.s fr8, @-r15
++ fmov.s fr7, @-r15
++ fmov.s fr6, @-r15
++ fmov.s fr5, @-r15
++ fmov.s fr4, @-r15
++#endif
++ sts.l pr, @-r15
++/* Note - The PLT entries have been "optimised" not to use r2. r2 is used by
++ GCC to return the address of large structures, so it should not be
++ corrupted here. This does mean however, that those PLTs does not conform
++ to the SH PIC ABI. That spec says that r0 contains the type of the PLT
++ and r2 contains the GOT id. The GNU Plt version stores the GOT id in r0 and
++ ignores the type. We can easily detect this difference however,
++ since the type will always be 0 or 8, and the GOT ids will always be
++ greater than or equal to 12.
++
++ Found in binutils/bfd/elf32-sh.c by Stefan Allius <allius@atecom.com>
++ */
++ mov #8 ,r5
++ cmp/gt r5, r0
++ bt 1f
++ mov r2, r0 ! link map address in r2 (SH PIC ABI)
++1:
++ mov r0, r4 ! link map address in r0 (GNUs PLT)
++ mova .LG, r0
++ mov.l .LG, r5
++ add r5, r0
++ mov.l 3f, r5
++ mov.l @(r0, r5),r5
++ jsr @r5
++ mov r1, r5 ! Reloc offset
++
++ lds.l @r15+, pr ! Get register content back
++
++#ifdef HAVE_FPU
++ fmov.s @r15+, fr4
++ fmov.s @r15+, fr5
++ fmov.s @r15+, fr6
++ fmov.s @r15+, fr7
++ fmov.s @r15+, fr8
++ fmov.s @r15+, fr9
++ fmov.s @r15+, fr10
++ fmov.s @r15+, fr11
++ lds.l @r15+, fpscr
++#endif
++
++ mov.l @r15+, r3
++ shal r3 ! Load T flag
++ mov.l @r15+, r12
++ mov.l @r15+, r7
++ mov.l @r15+, r6
++ mov.l @r15+, r5
++ mov.l @r15+, r4
++ jmp @r0 ! Jump to function address
++ mov.l @r15+, r3
++
++ .balign 4
++
++3:
++ .long _dl_linux_resolver@GOT
++.LG:
++ .long _GLOBAL_OFFSET_TABLE_
++ .size _dl_linux_resolve, . - _dl_linux_resolve
++
+diff -urN uClibc/ldso-0.9.24/ldso/sparc/boot1_arch.h uClibc.ldso.24/ldso-0.9.24/ldso/sparc/boot1_arch.h
+--- uClibc/ldso-0.9.24/ldso/sparc/boot1_arch.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sparc/boot1_arch.h 2002-08-08 09:35:49.000000000 -0500
+@@ -0,0 +1,7 @@
++/* Any assmbly language/system dependent hacks needed to setup boot1.c so it
++ * will work as expected and cope with whatever platform specific wierdness is
++ * needed for this architecture. See arm/boot1_arch.h for an example of what
++ * can be done.
++ */
++
++#define LD_BOOT(X) void _dl_boot (X)
+diff -urN uClibc/ldso-0.9.24/ldso/sparc/elfinterp.c uClibc.ldso.24/ldso-0.9.24/ldso/sparc/elfinterp.c
+--- uClibc/ldso-0.9.24/ldso/sparc/elfinterp.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sparc/elfinterp.c 2002-11-05 12:21:12.000000000 -0600
+@@ -0,0 +1,357 @@
++/* vi: set sw=4 ts=4: */
++/* sparc ELF shared library loader suppport
++ *
++ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
++ * David Engel, Hongjiu Lu and Mitch D'Souza
++ *
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. The name of the above contributors may not be
++ * used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#if defined (__SUPPORT_LD_DEBUG__)
++static const 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. */
++
++extern _dl_linux_resolve(void);
++
++unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
++{
++ int reloc_type;
++ Elf32_Rela * this_reloc;
++ char * strtab;
++ Elf32_Sym * symtab;
++ 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 = (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 = (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 = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
++ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
++
++ _dl_dprintf(2, "tpnt = %x\n", tpnt);
++ _dl_dprintf(2, "reloc = %x\n", this_reloc);
++ _dl_dprintf(2, "symtab = %x\n", symtab);
++ _dl_dprintf(2, "strtab = %x\n", strtab);
++
++
++ if (reloc_type != R_SPARC_JMP_SLOT) {
++ _dl_dprintf(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_dprintf(2, "symtab_index %d\n", symtab_index);
++
++#ifdef __SUPPORT_LD_DEBUG__
++ if (_dl_debug_symbols) {
++ _dl_dprintf(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, tpnt, resolver);
++ if(!new_addr) {
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ _dl_exit(31);
++ };
++
++#if defined (__SUPPORT_LD_DEBUG__)
++ if ((unsigned long) got_addr < 0x40000000)
++ {
++ if (_dl_debug_bindings)
++ {
++ _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
++ strtab + symtab[symtab_index].st_name);
++ if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
++ "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
++ }
++ }
++ if (!_dl_debug_nofixups) {
++ 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_dprintf(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;
++ Elf32_Sym * symtab;
++ Elf32_Rela * rpnt;
++ unsigned int * reloc_addr;
++
++ /* Now parse the relocation information */
++ rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++
++ symtab = (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(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_dprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if(symtab_index) _dl_dprintf(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;
++ Elf32_Sym * symtab;
++ Elf32_Rela * rpnt;
++ unsigned int * reloc_addr;
++ unsigned int symbol_addr;
++ int symtab_index;
++ /* Now parse the relocation information */
++
++ rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++
++ symtab = (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(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,
++ (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), symbolrel);
++
++ if(!symbol_addr &&
++ ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ goof++;
++ };
++ };
++ switch(reloc_type){
++ case R_SPARC_NONE:
++ break;
++ case R_SPARC_32:
++ *reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_SPARC_DISP32:
++ *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
++ break;
++ case R_SPARC_GLOB_DAT:
++ *reloc_addr = symbol_addr + rpnt->r_addend;
++ break;
++ case R_SPARC_JMP_SLOT:
++ reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
++ reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
++ break;
++ case R_SPARC_RELATIVE:
++ *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
++ break;
++ case R_SPARC_HI22:
++ if (!symbol_addr)
++ symbol_addr = tpnt->loadaddr + rpnt->r_addend;
++ else
++ symbol_addr += rpnt->r_addend;
++ *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
++ break;
++ case R_SPARC_LO10:
++ if (!symbol_addr)
++ symbol_addr = tpnt->loadaddr + rpnt->r_addend;
++ else
++ symbol_addr += rpnt->r_addend;
++ *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
++ break;
++ case R_SPARC_WDISP30:
++ *reloc_addr = (*reloc_addr & 0xc0000000)|
++ ((symbol_addr - (unsigned int) reloc_addr) >> 2);
++ break;
++ case R_SPARC_COPY:
++#if 0 /* This one is done later */
++ _dl_dprintf(2, "Doing copy for symbol ");
++ if(symtab_index) _dl_dprintf(2, strtab + symtab[symtab_index].st_name);
++ _dl_dprintf(2, "\n");
++ _dl_memcpy((void *) symtab[symtab_index].st_value,
++ (void *) symbol_addr,
++ symtab[symtab_index].st_size);
++#endif
++ break;
++ default:
++ _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
++#if defined (__SUPPORT_LD_DEBUG__)
++ _dl_dprintf(2, "%s ", _dl_reltypes[reloc_type]);
++#endif
++ if (symtab_index)
++ _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
++ _dl_exit(34);
++ };
++
++ };
++ return goof;
++}
++
++
++/* This is done as a separate step, because there are cases where
++ information is first copied and later initialized. This results in
++ the wrong information being copied. Someone at Sun was complaining about
++ a bug in the handling of _COPY by SVr4, and this may in fact be what he
++ was talking about. Sigh. */
++
++/* No, there are cases where the SVr4 linker fails to emit COPY relocs
++ at all */
++
++int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
++ int rel_size, int type)
++{
++ int i;
++ char * strtab;
++ int reloc_type;
++ int goof = 0;
++ Elf32_Sym * symtab;
++ 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 = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
++
++ symtab = (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(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, NULL, copyrel);
++ if(!symbol_addr) {
++ _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
++ _dl_progname, strtab + symtab[symtab_index].st_name);
++ goof++;
++ };
++ };
++ if (!goof)
++ _dl_memcpy((char *) symtab[symtab_index].st_value,
++ (char *) symbol_addr,
++ symtab[symtab_index].st_size);
++ };
++ return goof;
++}
++
++
+diff -urN uClibc/ldso-0.9.24/ldso/sparc/ld_syscalls.h uClibc.ldso.24/ldso-0.9.24/ldso/sparc/ld_syscalls.h
+--- uClibc/ldso-0.9.24/ldso/sparc/ld_syscalls.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sparc/ld_syscalls.h 2002-03-19 04:43:35.000000000 -0600
+@@ -0,0 +1,155 @@
++/*
++ * This file contains the system call macros and syscall
++ * numbers used by the shared library loader.
++ */
++
++#define __NR_exit 1
++#define __NR_read 3
++#define __NR_write 4
++#define __NR_open 5
++#define __NR_close 6
++#define __NR_getuid 24
++#define __NR_getgid 47
++#define __NR_geteuid 49
++#define __NR_getegid 50
++#define __NR_readlink 58
++#define __NR_mmap 71
++#define __NR_munmap 73
++#define __NR_stat 38
++#define __NR_mprotect 74
++
++/* Here are the macros which define how this platform makes
++ * system calls. This particular variant does _not_ set
++ * errno (note how it is disabled in __syscall_return) since
++ * these will get called before the errno symbol is dynamicly
++ * linked. */
++
++#define _syscall0(type,name) \
++type name(void) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res)\
++ : "r" (__g1) \
++ : "o0", "cc"); \
++if (__res < -255 || __res >= 0) \
++ return (type) __res; \
++/*errno = -__res; */\
++return -1; \
++}
++
++#define _syscall1(type,name,type1,arg1) \
++type name(type1 arg1) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++register long __o0 __asm__ ("o0") = (long)(arg1); \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res), "=&r" (__o0) \
++ : "1" (__o0), "r" (__g1) \
++ : "cc"); \
++if (__res < -255 || __res >= 0) \
++ return (type) __res; \
++/*errno = -__res;*/ \
++return -1; \
++}
++
++#define _syscall2(type,name,type1,arg1,type2,arg2) \
++type name(type1 arg1,type2 arg2) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++register long __o0 __asm__ ("o0") = (long)(arg1); \
++register long __o1 __asm__ ("o1") = (long)(arg2); \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res), "=&r" (__o0) \
++ : "1" (__o0), "r" (__o1), "r" (__g1) \
++ : "cc"); \
++if (__res < -255 || __res >= 0) \
++ return (type) __res; \
++/*errno = -__res;*/ \
++return -1; \
++}
++
++#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
++type name(type1 arg1,type2 arg2,type3 arg3) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++register long __o0 __asm__ ("o0") = (long)(arg1); \
++register long __o1 __asm__ ("o1") = (long)(arg2); \
++register long __o2 __asm__ ("o2") = (long)(arg3); \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res), "=&r" (__o0) \
++ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) \
++ : "cc"); \
++if (__res < -255 || __res>=0) \
++ return (type) __res; \
++/*errno = -__res;*/ \
++return -1; \
++}
++
++#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
++type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++register long __o0 __asm__ ("o0") = (long)(arg1); \
++register long __o1 __asm__ ("o1") = (long)(arg2); \
++register long __o2 __asm__ ("o2") = (long)(arg3); \
++register long __o3 __asm__ ("o3") = (long)(arg4); \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res), "=&r" (__o0) \
++ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__o3), "r" (__g1) \
++ : "cc"); \
++if (__res < -255 || __res>=0) \
++ return (type) __res; \
++/*errno = -__res;*/ \
++return -1; \
++}
++
++#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
++ type5,arg5) \
++type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
++{ \
++long __res; \
++register long __g1 __asm__ ("g1") = __NR_##name; \
++register long __o0 __asm__ ("o0") = (long)(arg1); \
++register long __o1 __asm__ ("o1") = (long)(arg2); \
++register long __o2 __asm__ ("o2") = (long)(arg3); \
++register long __o3 __asm__ ("o3") = (long)(arg4); \
++register long __o4 __asm__ ("o4") = (long)(arg5); \
++__asm__ __volatile__ ("t 0x10\n\t" \
++ "bcc 1f\n\t" \
++ "mov %%o0, %0\n\t" \
++ "sub %%g0, %%o0, %0\n\t" \
++ "1:\n\t" \
++ : "=r" (__res), "=&r" (__o0) \
++ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__o3), "r" (__o4), "r" (__g1) \
++ : "cc"); \
++if (__res < -255 || __res>=0) \
++ return (type) __res; \
++/*errno = -__res; */\
++return -1; \
++}
+diff -urN uClibc/ldso-0.9.24/ldso/sparc/ld_sysdep.h uClibc.ldso.24/ldso-0.9.24/ldso/sparc/ld_sysdep.h
+--- uClibc/ldso-0.9.24/ldso/sparc/ld_sysdep.h 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sparc/ld_sysdep.h 2002-08-09 08:05:29.000000000 -0500
+@@ -0,0 +1,112 @@
++
++/*
++ * Various assmbly language/system dependent hacks that are required
++ * so that we can minimize the amount of platform specific code.
++ */
++#define LINUXBIN
++
++/*
++ * Define this if the system uses RELOCA.
++ */
++#define ELF_USES_RELOCA
++
++/*
++ * Get a pointer to the argv array. On many platforms this can be just
++ * the address if the first argument, on other platforms we need to
++ * do something a little more subtle here. We assume that argc is stored
++ * at the word just below the argvp that we return here.
++ */
++#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
++
++/*
++ * Initialization sequence for a GOT. For the Sparc, this points to the
++ * PLT, and we need to initialize a couple of the slots. The PLT should
++ * look like:
++ *
++ * save %sp, -64, %sp
++ * call _dl_linux_resolve
++ * nop
++ * .word implementation_dependent
++ */
++#define INIT_GOT(GOT_BASE,MODULE) \
++{ \
++ GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
++ GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
++ GOT_BASE[2] = 0x01000000; /* nop */ \
++ GOT_BASE[3] = (int) MODULE; \
++}
++
++/*
++ * Here is a macro to perform a relocation. This is only used when
++ * bootstrapping the dynamic loader.
++ */
++#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
++ switch(ELF32_R_TYPE((RELP)->r_info)) { \
++ case R_SPARC_32: \
++ *REL = SYMBOL + (RELP)->r_addend; \
++ break; \
++ case R_SPARC_GLOB_DAT: \
++ *REL = SYMBOL + (RELP)->r_addend; \
++ break; \
++ case R_SPARC_JMP_SLOT: \
++ REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
++ REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
++ break; \
++ case R_SPARC_NONE: \
++ break; \
++ case R_SPARC_WDISP30: \
++ break; \
++ case R_SPARC_RELATIVE: \
++ *REL += (unsigned int) LOAD + (RELP)->r_addend; \
++ break; \
++ default: \
++ _dl_exit(1); \
++ }
++
++
++/*
++ * Transfer control to the user's application, once the dynamic loader
++ * is done. The crt calls atexit with $g1 if not null, so we need to
++ * ensure that it contains NULL.
++ */
++
++#define START() \
++ __asm__ volatile ( \
++ "add %%g0,%%g0,%%g1\n\t" \
++ "jmpl %0, %%o7\n\t" \
++ "restore %%g0,%%g0,%%g0\n\t" \
++ : /*"=r" (status) */ : \
++ "r" (_dl_elf_main): "g1", "o0", "o1")
++
++
++
++/* Here we define the magic numbers that this dynamic loader should accept */
++
++#define MAGIC1 EM_SPARC
++#undef MAGIC2
++/* Used for error messages */
++#define ELF_TARGET "Sparc"
++
++#ifndef COMPILE_ASM
++extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
++ unsigned int * i);
++#endif
++
++/*
++ * Define this if you want a dynamic loader that works on Solaris.
++ */
++#define SOLARIS_COMPATIBLE
++
++#define do_rem(result, n, base) result = (n % base)
++
++/*
++ * dbx wants the binder to have a specific name. Mustn't disappoint it.
++ */
++#ifdef SOLARIS_COMPATIBLE
++#define _dl_linux_resolve _elf_rtbndr
++#endif
++
++/* 4096 bytes alignment */
++#define PAGE_ALIGN 0xfffff000
++#define ADDR_ALIGN 0xfff
++#define OFFS_ALIGN 0x7ffff000
+diff -urN uClibc/ldso-0.9.24/ldso/sparc/resolve.S uClibc.ldso.24/ldso-0.9.24/ldso/sparc/resolve.S
+--- uClibc/ldso-0.9.24/ldso/sparc/resolve.S 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/ldso/sparc/resolve.S 2002-01-11 13:57:41.000000000 -0600
+@@ -0,0 +1,25 @@
++/*
++ * These are various helper routines that are needed to run an ELF image.
++ */
++#define COMPILE_ASM
++#include "ld_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 -urN uClibc/ldso-0.9.24/libdl/.cvsignore uClibc.ldso.24/ldso-0.9.24/libdl/.cvsignore
+--- uClibc/ldso-0.9.24/libdl/.cvsignore 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/libdl/.cvsignore 2001-04-26 11:12:47.000000000 -0500
+@@ -0,0 +1,2 @@
++libdl.so*
++
+diff -urN uClibc/ldso-0.9.24/libdl/Makefile uClibc.ldso.24/ldso-0.9.24/libdl/Makefile
+--- uClibc/ldso-0.9.24/libdl/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/libdl/Makefile 2004-03-01 03:05:53.000000000 -0600
+@@ -0,0 +1,86 @@
++# Makefile for uClibc
++#
++# Copyright (C) 2000 by Lineo, inc.
++# Copyright (C) 2000-2002 Erik Andersen <andersen@uclibc.org>
++#
++# This program 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.
++#
++# 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 Library General Public License for more
++# details.
++#
++# You should have received a copy of the GNU Library General Public License
++# along with this program; if not, write to the Free Software Foundation, Inc.,
++# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++
++TOPDIR=../../
++include $(TOPDIR)Rules.mak
++
++XXFLAGS=$(XWARNINGS) $(OPTIMIZATION) $(XARCH_CFLAGS) $(CPU_CFLAGS) \
++ -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
++ -fno-builtin -nostdinc -D_LIBC -I$(TOPDIR)ldso-0.9.24/include -I. -I$(TOPDIR)include
++
++ifeq ($(DODEBUG),y)
++XXFLAGS=$(XWARNINGS) -O0 -g3 $(XARCH_CFLAGS) $(CPU_CFLAGS) \
++ -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
++ -fno-builtin -nostdinc -D_LIBC -I$(TOPDIR)ldso-0.9.24/include -I. -I$(TOPDIR)include
++endif
++
++XXFLAGS+=$(shell $(CC) -print-search-dirs | sed -ne "s/install: *\(.*\)/-I\1include/gp")
++XXFLAGS_NOPIC:=$(XXFLAGS)
++ifeq ($(DOPIC),y)
++ XXFLAGS += $(PICFLAG) -D__LIBDL_SHARED__
++endif
++ifeq ($(strip $(SUPPORT_LD_DEBUG)),y)
++XXFLAGS+=-D__SUPPORT_LD_DEBUG__
++endif
++
++LIBDL=libdl.a
++LIBDL_PIC=libdl_pic.a
++LIBDL_SHARED=libdl.so
++LIBDL_SHARED_FULLNAME=libdl-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
++
++CSRC=dlib.c
++OBJS=dlib.o
++PIC_OBJS=dlib_pic.o
++
++all: $(OBJS) $(LIBDL) shared
++
++$(LIBDL): ar-target
++
++ar-target: $(OBJS) $(PIC_OBJS)
++ $(AR) $(ARFLAGS) $(LIBDL) ../ldso/$(TARGET_ARCH)/resolve.o $(OBJS)
++ $(AR) $(ARFLAGS) $(LIBDL_PIC) $(PIC_OBJS)
++ $(INSTALL) -d $(TOPDIR)lib
++ $(RM) $(TOPDIR)lib/$(LIBDL)
++ $(INSTALL) -m 644 $(LIBDL) $(TOPDIR)lib
++
++
++dlib.o: dlib.c
++ $(CC) $(XXFLAGS_NOPIC) -c dlib.c -o dlib.o
++ $(STRIPTOOL) -x -R .note -R .comment $*.o
++
++dlib_pic.o: dlib.c
++ $(CC) $(XXFLAGS) -c dlib.c -o dlib_pic.o
++ $(STRIPTOOL) -x -R .note -R .comment $*.o
++
++$(OBJ): Makefile
++
++shared:
++ $(LD) $(LDFLAGS) -soname=$(LIBDL_SHARED).$(MAJOR_VERSION) \
++ -o $(LIBDL_SHARED_FULLNAME) --whole-archive $(LIBDL_PIC) \
++ --no-whole-archive $(TOPDIR)/libc/misc/internals/interp.o \
++ -L$(TOPDIR)/lib -lc $(LDADD_LIBFLOAT) $(LIBGCC);
++ $(INSTALL) -d $(TOPDIR)lib
++ $(RM) $(TOPDIR)lib/$(LIBDL_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBDL_SHARED).$(MAJOR_VERSION)
++ $(INSTALL) -m 644 $(LIBDL_SHARED_FULLNAME) $(TOPDIR)lib
++ $(LN) -sf $(LIBDL_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBDL_SHARED)
++ $(LN) -sf $(LIBDL_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBDL_SHARED).$(MAJOR_VERSION)
++
++clean:
++ $(RM) .depend $(LIBDL_SHARED)* $(LIBDL_SHARED_FULLNAME) core *.o *.a *.s *.i tmp_make foo *~
+diff -urN uClibc/ldso-0.9.24/libdl/dlib.c uClibc.ldso.24/ldso-0.9.24/libdl/dlib.c
+--- uClibc/ldso-0.9.24/libdl/dlib.c 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/libdl/dlib.c 2004-03-01 03:04:42.000000000 -0600
+@@ -0,0 +1,664 @@
++/*
++ * libdl.c
++ *
++ * Functions required for dlopen et. al.
++ */
++
++#include <ldso.h>
++
++
++/* The public interfaces */
++void *dlopen(const char *, int) __attribute__ ((__weak__, __alias__ ("_dlopen")));
++int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
++void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
++const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
++int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
++void _dlinfo(void);
++
++
++#ifdef __LIBDL_SHARED__
++/* This is a real hack. We need access to the dynamic linker, but we
++also need to make it possible to link against this library without any
++unresolved externals. We provide these weak symbols to make the link
++possible, but at run time the normal symbols are accessed. */
++static void __attribute__ ((unused)) foobar(void)
++{
++ const char msg[]="libdl library not correctly linked\n";
++ _dl_write(2, msg, _dl_strlen(msg));
++ _dl_exit(1);
++}
++
++static int __attribute__ ((unused)) foobar1 = (int) foobar; /* Use as pointer */
++extern void _dl_dprintf(int, const char *, ...) __attribute__ ((__weak__, __alias__ ("foobar")));
++extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, enum caller_type)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **, struct elf_resolve *, char *)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++extern struct elf_resolve * _dl_check_if_named_library_is_loaded(const char *full_libname)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++extern int _dl_fixup(struct elf_resolve *tpnt, int lazy)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++extern int _dl_copy_fixups(struct dyn_elf * tpnt)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++#ifdef __mips__
++extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
++ __attribute__ ((__weak__, __alias__ ("foobar")));
++#endif
++#ifdef USE_CACHE
++int _dl_map_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
++int _dl_unmap_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
++#endif
++
++extern struct dyn_elf *_dl_symbol_tables __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern struct dyn_elf *_dl_handles __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern unsigned long _dl_error_number __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__, __alias__ ("foobar1")));
++#ifdef __SUPPORT_LD_DEBUG__
++extern char *_dl_debug __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_symbols __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_move __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_reloc __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_detail __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_nofixups __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern char *_dl_debug_bindings __attribute__ ((__weak__, __alias__ ("foobar1")));
++extern int _dl_debug_file __attribute__ ((__weak__, __alias__ ("foobar1")));
++#endif
++
++#else /* __LIBDL_SHARED__ */
++
++#ifdef __SUPPORT_LD_DEBUG__
++char *_dl_debug = 0;
++char *_dl_debug_symbols = 0;
++char *_dl_debug_move = 0;
++char *_dl_debug_reloc = 0;
++char *_dl_debug_detail = 0;
++char *_dl_debug_nofixups = 0;
++char *_dl_debug_bindings = 0;
++int _dl_debug_file = 2;
++#endif
++char *_dl_library_path = 0;
++char *_dl_ldsopath = 0;
++struct r_debug *_dl_debug_addr = NULL;
++static char *_dl_malloc_addr, *_dl_mmap_zero;
++#include "../ldso/_dl_progname.h" /* Pull in the name of ld.so */
++#include "../ldso/hash.c"
++#define _dl_trace_loaded_objects 0
++#include "../ldso/readelflib1.c"
++void *(*_dl_malloc_function) (size_t size);
++int _dl_fixup(struct elf_resolve *tpnt, int lazy);
++#endif
++
++static int do_dlclose(void *, int need_fini);
++
++
++static const char *dl_error_names[] = {
++ "",
++ "File not found",
++ "Unable to open /dev/zero",
++ "Not an ELF file",
++#if defined (__i386__)
++ "Not i386 binary",
++#elif defined (__sparc__)
++ "Not sparc binary",
++#elif defined (__mc68000__)
++ "Not m68k binary",
++#else
++ "Unrecognized binary type",
++#endif
++ "Not an ELF shared library",
++ "Unable to mmap file",
++ "No dynamic section",
++#ifdef ELF_USES_RELOCA
++ "Unable to process REL relocs",
++#else
++ "Unable to process RELA relocs",
++#endif
++ "Bad handle",
++ "Unable to resolve symbol"
++};
++
++static void __attribute__ ((destructor)) dl_cleanup(void)
++{
++ struct dyn_elf *d;
++
++ for (d = _dl_handles; d; d = d->next_handle)
++ if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI]) {
++ (* ((int (*)(void)) (d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI]))) ();
++ d->dyn->dynamic_info[DT_FINI] = 0;
++ }
++}
++
++void *_dlopen(const char *libname, int flag)
++{
++ struct elf_resolve *tpnt, *tfrom, *tcurr;
++ struct dyn_elf *dyn_chain, *rpnt = NULL;
++ struct dyn_elf *dpnt;
++ static int dl_init = 0;
++ ElfW(Addr) from;
++ struct elf_resolve *tpnt1;
++ void (*dl_brk) (void);
++
++ /* A bit of sanity checking... */
++ if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
++ _dl_error_number = LD_BAD_HANDLE;
++ return NULL;
++ }
++
++ from = (ElfW(Addr)) __builtin_return_address(0);
++
++ /* Have the dynamic linker use the regular malloc function now */
++ if (!dl_init) {
++ dl_init++;
++ _dl_malloc_function = malloc;
++ }
++
++ /* Cover the trivial case first */
++ if (!libname)
++ return _dl_symbol_tables;
++
++ _dl_map_cache();
++
++ /*
++ * Try and locate the module we were called from - we
++ * need this so that we get the correct RPATH. Note that
++ * this is the current behavior under Solaris, but the
++ * ABI+ specifies that we should only use the RPATH from
++ * the application. Thus this may go away at some time
++ * in the future.
++ */
++ tfrom = NULL;
++ for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
++ tpnt = dpnt->dyn;
++ if (tpnt->loadaddr < from
++ && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
++ tfrom = tpnt;
++ }
++
++ /* Try to load the specified library */
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
++#endif
++ tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname);
++ if (tpnt == NULL) {
++ _dl_unmap_cache();
++ return NULL;
++ }
++
++ dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
++ _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
++ dyn_chain->dyn = tpnt;
++ dyn_chain->flags = flag;
++ if (!tpnt->symbol_scope)
++ tpnt->symbol_scope = dyn_chain;
++
++ dyn_chain->next_handle = _dl_handles;
++ _dl_handles = rpnt = dyn_chain;
++
++ if (tpnt->init_flag & INIT_FUNCS_CALLED) {
++ /* If the init and fini stuff has already been run, that means
++ * the dlopen'd library has already been loaded, and nothing
++ * further needs to be done. */
++ return (void *) dyn_chain;
++ }
++
++
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
++#endif
++
++ for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
++ {
++ Elf32_Dyn *dpnt;
++ char *lpntstr;
++ for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
++ if (dpnt->d_tag == DT_NEEDED) {
++
++ char *name;
++ lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
++ dpnt->d_un.d_val);
++ name = _dl_get_last_path_component(lpntstr);
++
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n",
++ lpntstr, tcurr->libname);
++#endif
++
++ if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
++ goto oops;
++ }
++
++#if 1
++//FIXME: Enabling this is _so_ wrong....
++ /* We need global symbol resolution for everything
++ * in the dependent chain */
++ dyn_chain->flags |= RTLD_GLOBAL;
++#endif
++
++ rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
++ _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
++ rpnt = rpnt->next;
++ if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
++ rpnt->dyn = tpnt1;
++
++ }
++ }
++ }
++
++ /*
++ * OK, now attach the entire chain at the end
++ */
++ rpnt->next = _dl_symbol_tables;
++
++#ifdef __mips__
++ /*
++ * Relocation of the GOT entries for MIPS have to be done
++ * after all the libraries have been loaded.
++ */
++ _dl_perform_mips_global_got_relocations(tpnt);
++#endif
++
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
++#endif
++ /*
++ * 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 */
++ if (_dl_fixup(dyn_chain->dyn, dyn_chain->flags))
++ goto oops;
++
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
++#endif
++ if (_dl_symbol_tables) {
++ if (_dl_copy_fixups(dyn_chain))
++ goto oops;
++ }
++
++
++ /* TODO: Should we set the protections of all pages back to R/O now ? */
++
++
++ /* Notify the debugger we have added some objects. */
++ _dl_debug_addr->r_state = RT_ADD;
++ if (_dl_debug_addr) {
++ dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
++ if (dl_brk != NULL) {
++ _dl_debug_addr->r_state = RT_ADD;
++ (*dl_brk) ();
++
++ _dl_debug_addr->r_state = RT_CONSISTENT;
++ (*dl_brk) ();
++ }
++ }
++
++#if 0 //def __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dlinfo();
++#endif
++
++#ifdef __LIBDL_SHARED__
++ /* Find the last library so we can run things in the right order */
++ for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
++ ;
++
++ /* Run the ctors and set up the dtors */
++ for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
++ {
++ /* 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)
++ continue;
++ if (tpnt->libtype == elf_executable)
++ continue;
++ if (tpnt->init_flag & INIT_FUNCS_CALLED)
++ continue;
++ tpnt->init_flag |= INIT_FUNCS_CALLED;
++
++ if (tpnt->dynamic_info[DT_INIT]) {
++ void (*dl_elf_func) (void);
++ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
++ if (dl_elf_func && *dl_elf_func != NULL) {
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
++#endif
++ (*dl_elf_func) ();
++ }
++ }
++ if (tpnt->dynamic_info[DT_FINI]) {
++ void (*dl_elf_func) (void);
++ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
++ if (dl_elf_func && *dl_elf_func != NULL) {
++#ifdef __SUPPORT_LD_DEBUG__
++ if(_dl_debug)
++ _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
++#endif
++ atexit(dl_elf_func);
++ }
++ }
++ }
++#endif
++ return (void *) dyn_chain;
++
++oops:
++ /* Something went wrong. Clean up and return NULL. */
++ _dl_unmap_cache();
++ do_dlclose(dyn_chain, 0);
++ return NULL;
++}
++
++void *_dlsym(void *vhandle, const char *name)
++{
++ struct elf_resolve *tpnt, *tfrom;
++ struct dyn_elf *handle;
++ ElfW(Addr) from;
++ struct dyn_elf *rpnt;
++ void *ret;
++
++ handle = (struct dyn_elf *) vhandle;
++
++ /* First of all verify that we have a real handle
++ of some kind. Return NULL if not a valid handle. */
++
++ if (handle == NULL)
++ handle = _dl_symbol_tables;
++ else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
++ for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
++ if (rpnt == handle)
++ break;
++ if (!rpnt) {
++ _dl_error_number = LD_BAD_HANDLE;
++ return NULL;
++ }
++ } else if (handle == RTLD_NEXT) {
++ /*
++ * Try and locate the module we were called from - we
++ * need this so that we know where to start searching
++ * from. We never pass RTLD_NEXT down into the actual
++ * dynamic loader itself, as it doesn't know
++ * how to properly treat it.
++ */
++ from = (ElfW(Addr)) __builtin_return_address(0);
++
++ tfrom = NULL;
++ for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
++ tpnt = rpnt->dyn;
++ if (tpnt->loadaddr < from
++ && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
++ tfrom = tpnt;
++ handle = rpnt->next;
++ }
++ }
++ }
++
++ ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
++
++ /*
++ * Nothing found.
++ */
++ if (!ret)
++ _dl_error_number = LD_NO_SYMBOL;
++ return ret;
++}
++
++int _dlclose(void *vhandle)
++{
++ return do_dlclose(vhandle, 1);
++}
++
++static int do_dlclose(void *vhandle, int need_fini)
++{
++ struct dyn_elf *rpnt, *rpnt1;
++ struct dyn_elf *spnt, *spnt1;
++ ElfW(Phdr) *ppnt;
++ struct elf_resolve *tpnt;
++ int (*dl_elf_fini) (void);
++ void (*dl_brk) (void);
++ struct dyn_elf *handle;
++ unsigned int end;
++ int i = 0;
++
++ handle = (struct dyn_elf *) vhandle;
++ rpnt1 = NULL;
++ for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
++ if (rpnt == handle) {
++ break;
++ }
++ rpnt1 = rpnt;
++ }
++
++ if (!rpnt) {
++ _dl_error_number = LD_BAD_HANDLE;
++ return 1;
++ }
++
++ /* OK, this is a valid handle - now close out the file.
++ * We check if we need to call fini () on the handle. */
++ spnt = need_fini ? handle : handle->next;
++ for (; spnt; spnt = spnt1) {
++ spnt1 = spnt->next;
++
++ /* We appended the module list to the end - when we get back here,
++ quit. The access counts were not adjusted to account for being here. */
++ if (spnt == _dl_symbol_tables)
++ break;
++ if (spnt->dyn->usage_count == 1
++ && spnt->dyn->libtype == loaded_file) {
++ tpnt = spnt->dyn;
++ /* Apparently crt1 for the application is responsible for handling this.
++ * We only need to run the init/fini for shared libraries
++ */
++
++ if (tpnt->dynamic_info[DT_FINI]) {
++ dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
++ tpnt->dynamic_info[DT_FINI]);
++ (*dl_elf_fini) ();
++ }
++ }
++ }
++ if (rpnt1)
++ rpnt1->next_handle = rpnt->next_handle;
++ else
++ _dl_handles = rpnt->next_handle;
++
++ /* OK, this is a valid handle - now close out the file */
++ for (rpnt = handle; rpnt; rpnt = rpnt1) {
++ rpnt1 = rpnt->next;
++
++ /* We appended the module list to the end - when we get back here,
++ quit. The access counts were not adjusted to account for being here. */
++ if (rpnt == _dl_symbol_tables)
++ break;
++
++ rpnt->dyn->usage_count--;
++ if (rpnt->dyn->usage_count == 0
++ && rpnt->dyn->libtype == loaded_file) {
++ tpnt = rpnt->dyn;
++ /* Apparently crt1 for the application is responsible for handling this.
++ * We only need to run the init/fini for shared libraries
++ */
++#if 0
++
++ /* We have to do this above, before we start closing objects.
++ * Otherwise when the needed symbols for _fini handling are
++ * resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
++ if (tpnt->dynamic_info[DT_FINI]) {
++ dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
++ (*dl_elf_fini) ();
++ }
++#endif
++ end = 0;
++ for (i = 0, ppnt = rpnt->dyn->ppnt;
++ i < rpnt->dyn->n_phent; ppnt++, i++) {
++ if (ppnt->p_type != PT_LOAD)
++ continue;
++ if (end < ppnt->p_vaddr + ppnt->p_memsz)
++ end = ppnt->p_vaddr + ppnt->p_memsz;
++ }
++ _dl_munmap((void*)rpnt->dyn->loadaddr, end);
++ /* Next, remove rpnt->dyn from the loaded_module list */
++ if (_dl_loaded_modules == rpnt->dyn) {
++ _dl_loaded_modules = rpnt->dyn->next;
++ if (_dl_loaded_modules)
++ _dl_loaded_modules->prev = 0;
++ } else
++ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
++ if (tpnt->next == rpnt->dyn) {
++ tpnt->next = tpnt->next->next;
++ if (tpnt->next)
++ tpnt->next->prev = tpnt;
++ break;
++ }
++ free(rpnt->dyn->libname);
++ free(rpnt->dyn);
++ }
++ free(rpnt);
++ }
++
++
++ if (_dl_debug_addr) {
++ dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
++ if (dl_brk != NULL) {
++ _dl_debug_addr->r_state = RT_DELETE;
++ (*dl_brk) ();
++
++ _dl_debug_addr->r_state = RT_CONSISTENT;
++ (*dl_brk) ();
++ }
++ }
++
++ return 0;
++}
++
++const char *_dlerror(void)
++{
++ const char *retval;
++
++ if (!_dl_error_number)
++ return NULL;
++ retval = dl_error_names[_dl_error_number];
++ _dl_error_number = 0;
++ return retval;
++}
++
++/*
++ * Dump information to stderrr about the current loaded modules
++ */
++static char *type[] = { "Lib", "Exe", "Int", "Mod" };
++
++void _dlinfo(void)
++{
++ struct elf_resolve *tpnt;
++ struct dyn_elf *rpnt, *hpnt;
++
++ _dl_dprintf(2, "List of loaded modules\n");
++ /* First start with a complete list of all of the loaded files. */
++ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
++ _dl_dprintf(2, "\t%x %x %x %s %d %s\n",
++ (unsigned) tpnt->loadaddr, (unsigned) tpnt,
++ (unsigned) tpnt->symbol_scope,
++ type[tpnt->libtype],
++ tpnt->usage_count, tpnt->libname);
++ }
++
++ /* Next dump the module list for the application itself */
++ _dl_dprintf(2, "\nModules for application (%x):\n",
++ (unsigned) _dl_symbol_tables);
++ for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
++ _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
++
++ for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
++ _dl_dprintf(2, "Modules for handle %x\n", (unsigned) hpnt);
++ for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
++ _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn,
++ rpnt->dyn->libname);
++ }
++}
++
++int _dladdr(void *__address, Dl_info * __dlip)
++{
++ struct elf_resolve *pelf;
++ struct elf_resolve *rpnt;
++
++ _dl_map_cache();
++
++ /*
++ * Try and locate the module address is in
++ */
++ pelf = NULL;
++
++#if 0
++ _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
++#endif
++
++ for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
++ struct elf_resolve *tpnt;
++
++ tpnt = rpnt;
++#if 0
++ _dl_dprintf(2, "Module \"%s\" at %x\n",
++ tpnt->libname, tpnt->loadaddr);
++#endif
++ if (tpnt->loadaddr < (ElfW(Addr)) __address
++ && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
++ pelf = tpnt;
++ }
++ }
++
++ if (!pelf) {
++ return 0;
++ }
++
++ /*
++ * Try and locate the symbol of address
++ */
++
++ {
++ char *strtab;
++ Elf32_Sym *symtab;
++ int hn, si;
++ int sf;
++ int sn = 0;
++ ElfW(Addr) sa;
++
++ sa = 0;
++ symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
++ strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
++
++ sf = 0;
++ for (hn = 0; hn < pelf->nbucket; hn++) {
++ for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
++ ElfW(Addr) symbol_addr;
++
++ symbol_addr = pelf->loadaddr + symtab[si].st_value;
++ if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
++ sa = symbol_addr;
++ sn = si;
++ sf = 1;
++ }
++#if 0
++ _dl_dprintf(2, "Symbol \"%s\" at %x\n",
++ strtab + symtab[si].st_name, symbol_addr);
++#endif
++ }
++ }
++
++ if (sf) {
++ __dlip->dli_fname = pelf->libname;
++ __dlip->dli_fbase = (void *)pelf->loadaddr;
++ __dlip->dli_sname = strtab + symtab[sn].st_name;
++ __dlip->dli_saddr = (void *)sa;
++ }
++ return 1;
++ }
++}
+diff -urN uClibc/ldso-0.9.24/man/Makefile uClibc.ldso.24/ldso-0.9.24/man/Makefile
+--- uClibc/ldso-0.9.24/man/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/Makefile 2003-10-18 05:18:37.000000000 -0500
+@@ -0,0 +1,33 @@
++# Makefile for uClibc
++#
++# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org>
++#
++# This program 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.
++#
++# 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 Library General Public License for more
++# details.
++#
++# You should have received a copy of the GNU Library General Public License
++# along with this program; if not, write to the Free Software Foundation, Inc.,
++# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++#
++# Derived in part from the Linux-8086 C library, the GNU C Library, and several
++# other sundry sources. Files within this library are copyright by their
++# respective copyright holders.
++
++include ../Config.mk
++
++ALL = #ld.so.info
++
++all: $(ALL)
++
++ld.so.info: ld.so.texi
++ makeinfo $<
++
++clean:
++ $(RM) $(ALL) *~
+diff -urN uClibc/ldso-0.9.24/man/dlopen.3 uClibc.ldso.24/ldso-0.9.24/man/dlopen.3
+--- uClibc/ldso-0.9.24/man/dlopen.3 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/dlopen.3 2001-04-23 12:43:54.000000000 -0500
+@@ -0,0 +1,218 @@
++.\" -*- nroff -*-
++.\" Copyright 1995 Yggdrasil Computing, Incorporated.
++.\" written by Adam J. Richter (adam@yggdrasil.com),
++.\" with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com).
++.\"
++.\" This is free documentation; you can redistribute it and/or
++.\" modify it under the terms of the GNU General Public License as
++.\" published by the Free Software Foundation; either version 2 of
++.\" the License, or (at your option) any later version.
++.\"
++.\" The GNU General Public License's references to "object code"
++.\" and "executables" are to be interpreted as the output of any
++.\" document formatting or typesetting system, including
++.\" intermediate and printed output.
++.\"
++.\" This manual is distributed in the hope that it will be useful,
++.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
++.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++.\" GNU General Public License for more details.
++.\"
++.\" You should have received a copy of the GNU General Public
++.\" License along with this manual; if not, write to the Free
++.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
++.\" USA.
++.\"
++.TH DLOPEN 3 "16 May 1995" "Linux" "Linux Programmer's Manual"
++.SH NAME
++dlclose, dlerror, dlopen, dlsym \- Programming interface to dynamic linking loader.
++.SH SYNOPSIS
++.B #include <dlfcn.h>
++.sp
++.BI "void *dlopen (const char *" "filename" ", int " flag ");
++.br
++.BI "const char *dlerror(void);"
++.br
++.BI "void *dlsym(void *"handle ", char *"symbol ");"
++.br
++.BI "int dladdr(void *"address ", Dl_info *"dlip ");"
++.br
++.BI "int dlclose (void *"handle ");
++.sp
++Special symbols:
++.BR "_init" ", " "_fini" ". "
++.SH DESCRIPTION
++.B dlopen
++loads a dynamic library from the file named by the null terminated
++string
++.I filename
++and returns an opaque "handle" for the dynamic library.
++If
++.I filename
++is not an absolute path (i.e., it does not begin with a "/"), then the
++file is searched for in the following locations:
++.RS
++.PP
++A colon-separated list of directories in the user's
++\fBLD_LIBRARY\fP path environment variable.
++.PP
++The list of libraries specified in \fI/etc/ld.so.cache\fP.
++.PP
++\fI/usr/lib\fP, followed by \fI/lib\fP.
++.RE
++.PP
++If
++.I filename
++is a NULL pointer, then the returned handle is for the main program.
++.PP
++External references in the library are resolved using the libraries
++in that library's dependency list and any other libraries previously
++opened with the
++.B RTLD_GLOBAL
++flag.
++If the executable was linked
++with the flag "-rdynamic", then the global symbols in the executable
++will also be used to resolve references in a dynamically loaded
++library.
++.PP
++.I flag
++must be either
++.BR RTLD_LAZY ,
++meaning resolve undefined symbols as code from the dynamic library is
++executed, or
++.BR RTLD_NOW ,
++meaning resolve all undefined symbols before
++.B dlopen
++returns, and fail if this cannot be done.
++Optionally,
++.B RTLD_GLOBAL
++may be or'ed with
++.IR flag,
++in which case the external symbols defined in the library will be
++made available to subsequently loaded libraries.
++.PP
++If the library exports a routine named
++.BR _init ,
++then that code is executed before dlopen returns.
++If the same library is loaded twice with
++.BR dlopen() ,
++the same file handle is returned. The dl library maintains link
++counts for dynamic file handles, so a dynamic library is not
++deallocated until
++.B dlclose
++has been called on it as many times as
++.B dlopen
++has succeeded on it.
++.PP
++If
++.B dlopen
++fails for any reason, it returns NULL.
++A human readable string describing the most recent error that occurred
++from any of the dl routines (dlopen, dlsym or dlclose) can be
++extracted with
++.BR dlerror() .
++.B dlerror
++returns NULL if no errors have occurred since initialization or since
++it was last called. (Calling
++.B dlerror()
++twice consecutively, will always result in the second call returning
++NULL.)
++
++.B dlsym
++takes a "handle" of a dynamic library returned by dlopen and the null
++terminated symbol name, returning the address where that symbol is
++loaded. If the symbol is not found,
++.B dlsym
++returns NULL; however, the correct way to test for an error from
++.B dlsym
++is to save the result of
++.B dlerror
++into a variable, and then check if saved value is not NULL.
++This is because the value of the symbol could actually be NULL.
++It is also necessary to save the results of
++.B dlerror
++into a variable because if
++.B dlerror
++is called again, it will return NULL.
++.PP
++.B dladdr
++returns information about the shared library containing the memory
++location specified by
++.IR address .
++.B dladdr
++returns zero on success and non-zero on error.
++.PP
++.B dlclose
++decrements the reference count on the dynamic library handle
++.IR handle .
++If the reference count drops to zero and no other loaded libraries use
++symbols in it, then the dynamic library is unloaded. If the dynamic
++library exports a routine named
++.BR _fini ,
++then that routine is called just before the library is unloaded.
++.SH EXAMPLES
++.B Load the math library, and print the cosine of 2.0:
++.RS
++.nf
++.if t .ft CW
++#include <dlfcn.h>
++
++int main(int argc, char **argv) {
++ void *handle = dlopen ("/lib/libm.so", RTLD_LAZY);
++ double (*cosine)(double) = dlsym(handle, "cos");
++ printf ("%f\\n", (*cosine)(2.0));
++ dlclose(handle);
++}
++.if t .ft P
++.fi
++.PP
++If this program were in a file named "foo.c", you would build the program
++with the following command:
++.RS
++.LP
++gcc -rdynamic -o foo foo.c -ldl
++.RE
++.RE
++.LP
++.B Do the same thing, but check for errors at every step:
++.RS
++.nf
++.if t .ft CW
++#include <stdio.h>
++#include <dlfcn.h>
++
++int main(int argc, char **argv) {
++ void *handle;
++ double (*cosine)(double);
++ char *error;
++
++ handle = dlopen ("/lib/libm.so", RTLD_LAZY);
++ if (!handle) {
++ fputs (dlerror(), stderr);
++ exit(1);
++ }
++
++ cosine = dlsym(handle, "cos");
++ if ((error = dlerror()) != NULL) {
++ fputs(error, stderr);
++ exit(1);
++ }
++
++ printf ("%f\\n", (*cosine)(2.0));
++ dlclose(handle);
++}
++.if t .ft P
++.fi
++.RE
++.SH ACKNOWLEDGEMENTS
++The dlopen interface standard comes from Solaris.
++The Linux dlopen implementation was primarily written by
++Eric Youngdale with help from Mitch D'Souza, David Engel,
++Hongjiu Lu, Andreas Schwab and others.
++The manual page was written by Adam Richter.
++.SH SEE ALSO
++.BR ld(1) ,
++.BR ld.so(8) ,
++.BR ldconfig(8) ,
++.BR ldd(1) ,
++.BR ld.so.info .
+diff -urN uClibc/ldso-0.9.24/man/ld.so.8 uClibc.ldso.24/ldso-0.9.24/man/ld.so.8
+--- uClibc/ldso-0.9.24/man/ld.so.8 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/ld.so.8 2001-04-23 12:43:54.000000000 -0500
+@@ -0,0 +1,113 @@
++.TH ld.so 8 "14 March 1998"
++.SH NAME
++ld.so/ld-linux.so \- dynamic linker/loader
++.SH DESCRIPTION
++.B ld.so
++loads the shared libraries needed by a program, prepares the program
++to run, and then runs it.
++Unless explicitly specified via the
++.B \-static
++option to
++.B ld
++during compilation, all Linux programs are incomplete and require
++further linking at run time.
++.PP
++The necessary shared libraries needed by the program are searched for
++in the following order
++.IP o
++Using the environment variable
++.B LD_LIBRARY_PATH
++.RB ( LD_AOUT_LIBRARY_PATH
++for a.out programs).
++Except if the executable is a setuid/setgid binary, in which case it
++is ignored.
++.IP o
++From the cache file
++.BR /etc/ld.so.cache
++which contains a compiled list of candidate libraries previously found
++in the augmented library path.
++.IP o
++In the default path
++.BR /usr/lib ,
++and then
++.BR /lib .
++.SH ENVIRONMENT
++.TP
++.B LD_LIBRARY_PATH
++A colon-separated list of directories in which to search for
++ELF libraries at execution-time.
++Similar to the
++.B PATH
++environment variable.
++.TP
++.B LD_PRELOAD
++A whitespace-separated list of additional, user-specified, ELF shared
++libraries to be loaded before all others.
++This can be used to selectively override functions in other shared libraries.
++For setuid/setgid ELF binaries, only libraries in the standard search
++directories that are also setgid will be loaded.
++.TP
++.B LD_TRACE_LOADED_OBJECTS
++If present, causes the program to list its dynamic library dependencies,
++as if run by ldd, instead of running normally.
++.TP
++.B LD_BIND_NOW
++If present, causes the dynamic linker to resolve all symbols at program
++startup instead of when they are first referenced.
++.TP
++.B LD_AOUT_LIBRARY_PATH
++A colon-separated list of directories in which to search for
++a.out libraries at execution-time.
++Similar to the
++.B PATH
++environment variable.
++.TP
++.B LD_AOUT_PRELOAD
++The name of an additional, user-specified, a.out shared library to be loaded
++after all others.
++This can be used to selectively override functions in other shared libraries.
++.TP
++.B LD_NOWARN
++Suppress warnings about a.out libraries with incompatible minor
++version numbers.
++.TP
++.B LD_KEEPDIR
++Don't ignore the directory in the names of a.out libraries to be loaded.
++Use of this option is strongly discouraged.
++.SH FILES
++.PD 0
++.TP 20
++.B /lib/ld.so
++a.out dynamic linker/loader
++.TP 20
++.B /lib/ld-linux.so.*
++ELF dynamic linker/loader
++.TP
++.B /etc/ld.so.cache
++File containing a compiled list of directories in which to search for
++libraries and an ordered list of candidate libraries.
++.TP
++.B /etc/ld.so.preload
++File containing a whitespace separated list of ELF shared libraries to
++be loaded before the program.
++libraries and an ordered list of candidate libraries.
++.TP
++.B lib*.so*
++shared libraries
++.PD
++.SH SEE ALSO
++.BR ldd (1),
++.BR ldconfig (8).
++.SH BUGS
++.LP
++Currently
++.B ld.so
++has no means of unloading and searching for compatible or newer version of
++libraries.
++.PP
++.B ld.so
++functionality is only available for executables compiled using libc version
++4.4.3 or greater.
++.SH AUTHORS
++David Engel, Eric Youngdale, Peter MacDonald, Hongjiu Lu, Linus
++Torvalds, Lars Wirzenius and Mitch D'Souza (not necessarily in that order).
+diff -urN uClibc/ldso-0.9.24/man/ld.so.texi uClibc.ldso.24/ldso-0.9.24/man/ld.so.texi
+--- uClibc/ldso-0.9.24/man/ld.so.texi 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/ld.so.texi 2001-04-23 12:43:54.000000000 -0500
+@@ -0,0 +1,411 @@
++\input texinfo @c -*-texinfo-*-
++@c %**start of header
++@setfilename ld.so.info
++@settitle ld.so : Dynamic-Link Library support
++@c %**end of header
++
++@ifinfo
++This file documents the dynamic-link support libraries and utilities for the
++Linux OS, version 1.8.1.
++
++Copyright 1996 Michael Deutschmann
++
++This document is subject to the GNU General Public License as published by
++the Free Software foundation, version 2 or later (your choice).
++
++Note: The software described in this document is under a different copyright
++and license.
++
++@end ifinfo
++
++@titlepage
++@title ld.so
++@subtitle Dynamic Link library support for the Linux OS.
++@author David Engel
++@author Eric Youngdale
++@author Peter Macdonald
++@author Hongjiu Lu
++@author Mitch D'Souza
++@author Michael Deutschmann (this documentation)
++
++@page
++Copyright @copyright{} 1996 Michael Deutschmann
++
++This document is subject to the GNU General Public License as published by
++the Free Software foundation, version 2 or later (your choice).
++
++Note: The software described in this document is under a different copyright
++and license.
++@end titlepage
++
++@ifinfo
++@node Top
++@top
++
++The @code{ld.so} module provides dynamic linked library support in Linux.
++This file documents @code{ld.so} and its companion software.
++
++@menu
++* intro:: Introduction
++
++* ld.so:: The dynamic linker core program
++* ldd:: A utility to print out dependencies
++* ldconfig:: A utility to maintain the cache and symlinks
++* libdl:: Manual dynamic linking library
++@end menu
++
++@end ifinfo
++
++@node intro
++@unnumbered Introduction
++
++The @code{ld.so} suite contains special files and utilities needed for linux
++to handle @dfn{dynamic libraries}.
++
++Ordinary static libraries (@file{lib*.a} files) are included into executables
++that use their functions. A file that only uses static libraries needs less
++intelligence to load, but takes up more space. If many executables use the
++same library, there can be much wastage of storage space, since multiple
++copies of the library functions are scattered across the executables.
++However, static libraries are easier to make.
++
++Dynamic libraries (@file{lib*.so*} files) are not copied into executables ---
++the executable is written in such a way that it will automatically load the
++libraries. In linux, the executable will first load the special library
++@code{ld.so} or @code{ld-linux.so}, which contains the intelligence
++to load further dynamic libraries. Since multiple files end up getting
++executable data from the same file, dynamic libraries are also known as
++shared libraries.
++
++Linux executables come in two flavors, @sc{elf} and a.out.
++
++a.out is the original executable format used by Linux. It has somewhat less
++overhead than @sc{elf}. However creating shared libraries for a.out is
++@emph{very} involved, and each a.out shared library must be explicitly
++registered.
++
++@sc{elf} is a more recent format, which supports a much simpler method of
++creating libraries. @sc{elf} libraries may also be linked manually
++(@pxref{libdl}).
++
++Since many library authors prefer @sc{elf} and no longer release shared a.out
++libraries, a.out is moribund on Linux. This version of the @code{ld.so} can
++be compiled to support only @sc{elf}, or to support both formats. (The last
++release of ld.so to support a.out alone was 1.8.0.)
++
++@node ld.so
++@chapter @code{ld.so}: Dynamic linker core
++
++@code{ld.so} works behind the scenes to handle dynamic libraries in Linux.
++Users will almost never have to deal with it directly, but in special cases
++one can send instructions to it through environment variables. Also, if
++something is wrong with your libraries (usually an incorrect version) ld.so
++will give error messages.
++
++Actually @code{ld.so} is the a.out linker. The new @sc{elf} executables are
++handled by a related program @code{ld-linux.so}.
++
++@menu
++* files:: Configuration files used by the suite
++* environment:: Environment settings that tweak @code{ld.so}
++* errors:: Complaints @code{ld.so} might make
++@end menu
++
++@node files
++@section Configuration Files
++
++@table @file
++@item /etc/ld.so.cache
++A file created by @code{ldconfig} and used to speed linking. It's structure
++is private to the suite.
++
++@item /etc/ld.so.conf
++A simple list of directories to scan for libraries, in addition to
++@file{/usr/lib} and @file{/lib}, which are hardwired. It may contain
++comments started with a @samp{#}.
++
++@item /etc/ld.so.preload
++A list of libraries to preload. This allows preloading libraries for
++setuid/setgid executables securely. It may contain comments.
++@end table
++
++@node environment
++@section Environment Variables
++
++@table @code
++@item LD_AOUT_LIBRARY_PATH
++@itemx LD_LIBRARY_PATH
++These variables supply a library path for finding dynamic libraries, in the
++standard colon seperated format. These variables are ignored when executing
++setuid/setgid programs, because otherwise they would be a security hazard.
++@code{ld.so} will use @code{LD_AOUT_LIBRARY_PATH} and @code{ld-linux.so} will
++use @code{LD_LIBRARY_PATH}.
++
++@item LD_AOUT_PRELOAD
++@itemx LD_PRELOAD
++These variables allow an extra library not specified in the executable to be
++loaded. Generally this is only useful if you want to override a function.
++These are also ignored when running setuid/setgid executables. @code{ld.so}
++will use @code{LD_AOUT_PRELOAD} and @code{ld-linux.so} will use
++@code{LD_PRELOAD}.
++
++@item LD_NOWARN
++If non-empty, errors about incompatible minor revisions are suppressed.
++
++@item LD_KEEPDIR
++If non-empty, allow executables to specify absolute library names. This
++option is deprecated.
++@c FIXME:
++@c The following are things I noticed in the ld-linux.so source.
++@c I don't really understand 'em. Could someone help me?
++@c
++@c @item LD_BIND_NOW
++@c This option is used by the @code{ld-linux.so} only. I don't know
++@c what it does. (I suspect, looking at the code, that it specifies
++@c "RTLD_NOW" rather than "RTLD_LAZY" mode for the shared libraries.)
++@c
++@c @item LD_TRACE_LOADED_OBJECTS
++@c @itemx LD_WARN
++@c These seem to have something to do with the communication between the
++@c @code{ld-linux.so} and @code{ldd}. I don't know more.
++@end table
++
++@node errors
++@section Errors
++
++@table @samp
++@item Can't find library @var{library}
++The executable required a dynamically linked library that ld.so cannot find.
++Your symbolic links may be not set right, or you may have not installed a
++library needed by the program.
++
++@item Can't load library @var{library}
++The library is corrupt.
++
++@item Incompatible library @var{library}
++@itemx Require major version @var{x} and found @var{y}
++Your version of the library is incompatible with the executable. Recompiling
++the executable, or upgrading the library will fix the problem.
++
++@item using incompatible library @var{library}
++@itemx Desire minor version >= @var{x} and found @var{y}.
++Your version of the library is older than that expected by the executable,
++but not so old that the library interface has radically changed, so the
++linker will attempt to run anyway. There is a chance that it will work, but
++you should upgrade the library or recompile the software. The environment
++variable @code{LD_NOWARN} can be used to supress this message.
++
++@item too many directories in library path
++The linker only supports up to 32 library directories. You have too many.
++
++@item dynamic linker error in @var{blah}
++The linker is having trouble handling a binary - it is probably corrupt.
++
++@item can't map cache file @var{cache-file}
++@itemx cache file @var{cache-file} @var{blah}
++The linker cache file (generally @file{/etc/ld.so.cache}) is corrupt or
++non-existent. These errors can be ignored, and can be prevented by
++regenerating the cache file with @code{ldconfig}.
++@end table
++
++@node ldd
++@chapter @code{ldd}: Dependency scanner
++
++@code{ldd} is a utility that prints out the dynamic libraries that an
++executable is linked to.
++
++Actually @code{ldd} works by signalling ld.so to print the dependencies.
++For a.out executables this is done by starting the executable with
++@code{argc} equal to 0. The linker detects this and prints the dependencies.
++(This can cause problems with @emph{very} old binaries, which would run as
++normal only with an inappropriate @code{argc}.)
++
++For @sc{elf} executables, special environment variables are used to tell the
++linker to print the dependencies.
++
++@code{ldd} has a few options:
++
++@table @samp
++@item -v
++Print the version number of @code{ldd} itself
++
++@item -V
++Print the version number of the dynamic linker
++
++@item -d
++Report missing functions. This is only supported for @sc{elf} executables.
++
++@item -r
++Report missing objects. This is also only available for @sc{elf}
++executables.
++@end table
++
++@node ldconfig
++@chapter @code{ldconfig}: Setup program
++
++This utility is used by the system administrator to automatically set up
++symbolic links needed by the libraries, and also to set up the cache file.
++
++@code{ldconfig} is run after new dynamic libraries are installed, and if the
++cache file or links are damaged. It is also run when upgrading the
++@code{ld.so} suite itself.
++
++The @file{/lib} and @file{/usr/lib} directories, and any listed in the file
++@file{/etc/ld.so.conf} are scanned by default unless @samp{-n} is used.
++Additional directories may be specified on the command line.
++
++It has the following options:
++
++@table @samp
++@item -D
++Enter debug mode. Implies @samp{-N} and @samp{-X}.
++
++@item -v
++Verbose. Print out links created and directories scanned.
++
++@item -n
++Check directories specified on the commandline @emph{only}.
++
++@item -N
++Do not regenerate the cache.
++
++@item -X
++Do not rebuild symbolic links.
++
++@item -l
++Set up symbolic links for only libraries presented on the command line.
++
++@item -p
++Print out the library pathnames in the cache file (@file{/etc/ld.so.cache})
++@end table
++
++@node libdl
++@chapter User dynamic linking library
++
++The @code{ld.so} package includes a small library of functions
++(@code{libdl}) to allow manual dynamic linking. Normally programs are linked
++so that dynamic functions and objects are automagically available. These
++functions allow one to manually load and access a symbol from a library.
++They are only available for @sc{elf} executables.
++
++@menu
++* using libdl:: General points
++* functions:: How to use the functions
++* example:: A sample program
++@end menu
++
++@node using libdl
++@section Overview
++
++To access this library, add the flag @samp{-ldl} to your compile command when
++linking the executable. You also must include the header file
++@code{dlfcn.h}. You may also need the flag @samp{-rdynamic}, which enables
++resolving references in the loaded libraries against your executable.
++
++Generally, you will first use @code{dlopen} to open a library. Then you use
++@code{dlsym} one or more times to access symbols. Finally you use
++@code{dlclose} to close the library.
++
++These facilities are most useful for language interpreters that provide
++access to external libraries. Without @code{libdl}, it would be neccessary
++to link the interpreter executable with any and all external libraries
++needed by the programs it runs. With @code{libdl}, the interpreter only
++needs to be linked with the libraries it uses itself, and can dynamically
++load in additional ones if programs need it.
++
++@node functions
++@section Functions
++
++@deftypefun void *dlopen ( const char @var{filename}, int @var{flags} )
++
++This function opens the dynamic library specified by @var{filename}
++and returns an abstract handle, which can be used in subsequent calls to
++@code{dlsym}. The function will respect the @code{LD_ELF_LIBRARY_PATH} and
++@code{LD_LIBRARY_PATH} environment variables.
++
++@end deftypefun
++
++The following flags can be used with @code{dlopen}:
++
++@deftypevr Macro int RTLD_LAZY
++Resolve symbols in the library as they are needed.
++@end deftypevr
++
++@deftypevr Macro int RTLD_NOW
++Resolve all symbols in the library before returning, and fail if not all can
++be resolved. This is mutually exclusive with @code{RTLD_LAZY}.
++@end deftypevr
++
++@deftypevr Macro int RTLD_GLOBAL
++Make symbols in this library available for resolving symbols in other
++libraries loaded with @code{dlopen}.
++@end deftypevr
++
++@deftypefun int dlclose ( void *@var{handle} )
++
++This function releases a library handle.
++
++Note that if a library opened twice, the handle will be the same. However,
++a reference count is used, so you should still close the library as many
++times as you open it.
++
++@end deftypefun
++
++@deftypefun void *dlsym (void *@var{handle},char *@var{symbol-name})
++
++This function looks up the name @var{symbol-name} in the library and returns
++it in the void pointer.
++
++If there is an error, a null pointer will be returned. However, it is
++possible for a valid name in the library to have a null value, so
++@code{dlerror} should be used to check if there was an error.
++
++@end deftypefun
++
++@deftypefun {libdl function} {const char} *dlerror( void )
++
++This function is used to read the error state. It returns a human-readable
++string describing the last error, or null, meaning no error.
++
++The function resets the error value each time it is called, so the result
++should be copied into a variable. If the function is called more than once
++after an error, the second and subsequent calls will return null.
++
++@end deftypefun
++
++@node example
++@section Example program
++
++Here is an example program that prints the cosine of two by manually linking
++to the math library:
++
++@example
++@c The following was snarfed verbatim from the dlopen.3 man file.
++#include <stdio.h>
++#include <dlfcn.h>
++
++int main(int argc, char **argv) @{
++ void *handle;
++ double (*cosine)(double);
++ char *error;
++
++ handle = dlopen ("/lib/libm.so", RTLD_LAZY);
++ if (!handle) @{
++ fputs (dlerror(), stderr);
++ exit(1);
++ @}
++
++ cosine = dlsym(handle, "cos");
++ if ((error = dlerror()) != NULL) @{
++ fputs(error, stderr);
++ exit(1);
++ @}
++
++ printf ("%f\\n", (*cosine)(2.0));
++ dlclose(handle);
++@}
++@end example
++
++@contents
++
++@bye
+diff -urN uClibc/ldso-0.9.24/man/ldconfig.8 uClibc.ldso.24/ldso-0.9.24/man/ldconfig.8
+--- uClibc/ldso-0.9.24/man/ldconfig.8 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/ldconfig.8 2001-04-23 12:43:54.000000000 -0500
+@@ -0,0 +1,189 @@
++.TH ldconfig 8 "14 March 1998"
++.SH NAME
++ldconfig \- determine run-time link bindings
++.SH SYNOPSIS
++ldconfig
++.RB [ \-DvqnNX ]
++.RB [ \-f\ conf ]
++.RB [ \-C\ cache ]
++.RB [ \-r\ root ]
++.IR directory \ ...
++.PD 0
++.PP
++.PD
++ldconfig
++.B \-l
++.RB [ \-Dvq ]
++.IR library \ ...
++.PD 0
++.PP
++.PD
++ldconfig
++.B \-p
++.SH DESCRIPTION
++.B ldconfig
++creates the necessary links and cache (for use by the run-time linker,
++.IR ld.so )
++to the most recent shared libraries found in the directories specified
++on the command line, in the file
++.IR /etc/ld.so.conf ,
++and in the trusted directories
++.RI ( /usr/lib
++and
++.IR /lib ).
++.B ldconfig
++checks the header and file names of the libraries it encounters when
++determining which versions should have their links updated.
++.B ldconfig
++ignores symbolic links when scanning for libraries.
++.PP
++.B ldconfig
++will attempt to deduce the type of ELF libs (ie. libc5 or libc6/glibc)
++based on what C libs if any the library was linked against, therefore when
++making dynamic libraries, it is wise to explicitly link against libc (use -lc).
++.PP
++Some existing libs do not contain enough information to allow the deduction of
++their type, therefore the
++.IR /etc/ld.so.conf
++file format allows the specification of an expected type. This is
++.B only
++used for those ELF libs which we can not work out. The format
++is like this "dirname=TYPE", where type can be libc4, libc5 or libc6.
++(This syntax also works on the command line). Spaces are
++.B not
++allowed. Also see the
++.B -p
++option.
++.PP
++Directory names containing an
++.B = are no longer legal
++unless they also have an expected type specifier.
++.PP
++.B ldconfig
++should normally be run by the super-user as it may require write
++permission on some root owned directories and files.
++It is normally run automatically at bootup, from /etc/rc, or manually
++whenever new DLL's are installed.
++.SH OPTIONS
++.TP
++.B \-D
++Debug mode.
++Implies
++.B \-N
++and
++.BR \-X .
++.TP
++.B \-v
++Verbose mode.
++Print current version number, the name of each directory as it
++is scanned and any links that are created.
++Overrides quiet mode.
++.TP
++.B \-q
++Quiet mode.
++Don't print warnings.
++.TP
++.B \-n
++Only process directories specified on the command line.
++Don't process the trusted directories
++.RI ( /usr/lib
++and
++.IR /lib )
++nor those specified in
++.IR /etc/ld.so.conf .
++Implies
++.BR \-N .
++.TP
++.B \-N
++Don't rebuild the cache.
++Unless
++.B \-X
++is also specified, links are still updated.
++.TP
++.B \-X
++Don't update links.
++Unless
++.B \-N
++is also specified, the cache is still rebuilt.
++.TP
++.B \-f conf
++Use
++.B conf
++instead of
++.IR /etc/ld.so.conf .
++.TP
++.B \-C cache
++Use
++.B cache
++instead of
++.IR /etc/ld.so.cache .
++.TP
++.B \-r root
++Change to and use
++.B root
++as the root directory.
++.TP
++.B \-l
++Library mode.
++Manually link individual libraries.
++Intended for use by experts only.
++.TP
++.B \-p
++Print the lists of directories and candidate libraries stored in
++the current cache.
++.SH EXAMPLES
++In the bootup file
++.I /etc/rc
++having the line
++.RS
++
++/sbin/ldconfig -v
++
++.RE
++will set up the correct links for the shared binaries and rebuild
++the cache.
++.TP
++On the command line
++.RS
++
++# /sbin/ldconfig -n /lib
++
++.RE
++as root after the installation of a new DLL, will properly update the
++shared library symbolic links in /lib.
++
++.SH FILES
++.PD 0
++.TP 20
++.B /lib/ld.so
++execution time linker/loader
++.TP 20
++.B /etc/ld.so.conf
++File containing a list of colon, space, tab, newline, or comma spearated
++directories in which to search for libraries.
++.TP 20
++.B /etc/ld.so.cache
++File containing an ordered list of libraries found in the directories
++specified in
++.BR /etc/ld.so.conf .
++.TP
++.B lib*.so.version
++shared libraries
++.PD
++.SH SEE ALSO
++.BR ldd (1),
++.BR ld.so (8).
++.SH BUGS
++.LP
++.BR ldconfig 's
++functionality, in conjunction with
++.BR ld.so ,
++is only available for executables compiled using libc version 4.4.3 or greater.
++.PP
++.BR ldconfig ,
++being a user process, must be run manually and has no means of dynamically
++determining and relinking shared libraries for use by
++.BR ld.so
++when a new DLL is installed.
++.SH AUTHORS
++David Engel and Mitch D'Souza.
+diff -urN uClibc/ldso-0.9.24/man/ldd.1 uClibc.ldso.24/ldso-0.9.24/man/ldd.1
+--- uClibc/ldso-0.9.24/man/ldd.1 1969-12-31 18:00:00.000000000 -0600
++++ uClibc.ldso.24/ldso-0.9.24/man/ldd.1 2001-04-23 12:43:54.000000000 -0500
+@@ -0,0 +1,59 @@
++.\" Copyright 1995-2000 David Engel (david@ods.com)
++.\" Copyright 1995 Rickard E. Faith (faith@cs.unc.edu)
++.\" Most of this was copied from the README file. Do not restrict distribution.
++.\" May be distributed under the GNU General Public License
++.TH LDD 1 "14 March 1998"
++.SH NAME
++ldd \- print shared library dependencies
++.SH SYNOPSIS
++.B ldd
++.RB [ \-vVdr ]
++program|library ...
++.SH DESCRIPTION
++.B ldd
++prints the shared libraries required by each program or shared library
++specified on the command line.
++If a shared library name does not contain a '/',
++.B ldd
++attempts to locate the library in the standard locations.
++To run
++.B ldd
++on a shared library in the current directory, a "./" must be prepended
++to its name.
++.SH OPTIONS
++.TP
++.B \-v
++Print the version number of
++.BR ldd .
++.TP
++.B \-V
++Print the version number of the dynamic linker,
++.BR ld.so .
++.TP
++.B \-d
++Perform relocations and report any missing functions (ELF only).
++.TP
++.B \-r
++Perform relocations for both data objects and functions, and
++report any missing objects (ELF only).
++.SH BUGS
++.B ldd
++does not work very well on libc.so.5 itself.
++.PP
++.B ldd
++does not work on a.out shared libraries.
++.PP
++.B ldd
++does not work with some extremely old a.out programs which were
++built before
++.B ldd
++support was added to the compiler releases.
++If you use
++.B ldd
++on one of these programs, the program will attempt to run with argc = 0 and
++the results will be unpredictable.
++.SH AUTHOR
++David Engel.
++.SH SEE ALSO
++.BR ldconfig (8),
++.BR ld.so (8).