diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2004-03-05 19:06:24 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2004-03-05 19:06:24 +0000 |
commit | 9c12805bf3341becb4ff647bdfbfe5318e379468 (patch) | |
tree | 4943c79b54b56abe992e1b274eb45a463a232e6d | |
parent | de40cc62a0d5c276d4628470cc5217a495d5afac (diff) | |
download | buildroot-novena-9c12805bf3341becb4ff647bdfbfe5318e379468.tar.gz buildroot-novena-9c12805bf3341becb4ff647bdfbfe5318e379468.zip |
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.
-rw-r--r-- | make/uclibc.mk | 12 | ||||
-rw-r--r-- | sources/uClibc-ldso-0.9.24.patch | 11861 |
2 files changed, 11873 insertions, 0 deletions
diff --git a/make/uclibc.mk b/make/uclibc.mk index 22db81341..ff857aa49 100644 --- a/make/uclibc.mk +++ b/make/uclibc.mk @@ -44,6 +44,9 @@ endif #(cd $(BUILD_DIR) ; ln -s $(DL_DIR)/uClibc) #-mkdir $(UCLIBC_DIR) #(cd $(DL_DIR)/uClibc && tar cf - .) | (cd $(UCLIBC_DIR) && tar xvfp - ) +ifeq ($(strip $(USE_UCLIBC_LDSO_0_9_24)),true) + $(SOURCE_DIR)/patch-kernel.sh $(UCLIBC_DIR) $(SOURCE_DIR) uClibc-ldso-0.9.24.patch +endif touch $(UCLIBC_DIR)/.unpacked $(UCLIBC_DIR)/.configured: $(UCLIBC_DIR)/.unpacked $(LINUX_DIR)/.configured @@ -91,6 +94,15 @@ $(UCLIBC_DIR)/lib/libc.a: $(UCLIBC_DIR)/.configured $(LIBFLOAT_TARGET) RUNTIME_PREFIX=/ \ HOSTCC="$(HOSTCC)" \ all +ifeq ($(strip $(USE_UCLIBC_LDSO_0_9_24)),true) + #rm -rf $(UCLIBC_DIR)/ld-uClibc* $(UCLIBC_DIR)/libdl* + $(MAKE) -C $(UCLIBC_DIR)/ldso-0.9.24 \ + PREFIX= \ + DEVEL_PREFIX=$(REAL_GNU_TARGET_NAME)/ \ + RUNTIME_PREFIX=/ \ + HOSTCC="$(HOSTCC)" \ + all shared +endif $(STAGING_DIR)/$(REAL_GNU_TARGET_NAME)/lib/libc.a: $(UCLIBC_DIR)/lib/libc.a $(MAKE) -C $(UCLIBC_DIR) \ 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). |