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 +# +# 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 +#include + +#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 /* before elf.h to get ELF_USES_RELOCA right */ +#include +#include + +#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 +/* For MAP_ANONYMOUS -- differs between platforms */ +#include +/* 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 + + +/* 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 +/* Pull in compiler and arch stuff */ +#include +#include +/* Pull in the arch specific type information */ +#include +/* Now the ldso specific headers */ +#include +#include +#include +#include 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 +# +# 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<=i) { + m-=i; + i<<=1; + if(i&(1<<31)) + break; + if(i=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, + * + * 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 + 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 + * Copyright (C) 2002 Steven J. Hill + * + */ +.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 + */ + +.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 and + * Eddie C. Dost + * + * 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 + */ + + .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 + */ + 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 +# +# 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 + + +/* 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 +# +# 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 +.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 + +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 +#include + +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 +#include + +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).