Initial checkin for ld.so. This is a combination of effort from Manuel Novoa

III and me.  I've been working on stripping out arch dependant stuff and
replacing it with generic stuff whenever possible.
 -Erik
This commit is contained in:
Eric Andersen
2001-04-23 17:43:54 +00:00
parent c4a3f3f81e
commit 66f269d2a5
58 changed files with 13958 additions and 0 deletions

49
ldso/COPYRIGHT Normal file
View File

@@ -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.
*/

13
ldso/Makefile Normal file
View File

@@ -0,0 +1,13 @@
include Config.mk
SUBDIRS = util d-link # man
all:
set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d ; done
install: all
sh instldso.sh
clean:
set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
-find . -name '*~' | xargs rm -f

860
ldso/README Normal file
View File

@@ -0,0 +1,860 @@
Apr 20, 2001 -- Manuel Novoa III
Inital port for uClibc from debian ld.so_1.9.11-9.tar.gz.
Removed a.out support.
"make" generates the ld-linux-uclibc.so.1, libdl.so.1, ldd, ldconfig
suitable for the target platform.
"make DEVEL=true" generates the same files, but ld-linux-uclibc.so.1 and
ldconfig are modified to not conflict with the devel platform system
libs. (This is only of use if TARGET_ARCH == NATIVE_ARCH.) These
modified versions ignore /lib and /usr/lib and look for shared libs
only in $(INSTALL_DIR)/lib. The modified ldconfig writes ld.so.cache
in $(INSTALL_DIR)/etc.
The above assumes you've set the DYNAMIC_LINKER to /lib/ld-linux-uclibc.so.1
in extra/gcc-uClibc/Makefile.
Todo:
Remove unneeded code in util/ldd.c.
Link against static uClibc instead of using custom routines. ???
Lots more cleanup... especially the arch-dependent Makefiles.
****************** original ld.so.lsm file **************************
Begin3
Title: Linux shared, dynamic linker and utilities.
Version: 1.9.11
Entered-date: 01MAY99
Description: This package contains ld.so, ld-linux.so, ldconfig,
ldd and libdl.
Keywords: dynamic linker, shared library, ld.so, ld-linux.so,
ldconfig, ldd, libdl
Author: david@ods.com (David Engel)
Maintained-by: david@ods.com (David Engel)
Primary-site: tsx-11.mit.edu /pub/linux/packages/GCC
ld.so-1.9.11.tar.gz
Alternate-site: sunsite.unc.edu /pub/Linux/GCC
ld.so-1.9.11.tar.gz
Platform: Linux 2.0.0 or later.
Copying-policy: Copyrighted but freely distributable.
End
*********************************************************************
Original README starts here
*********************************************************************
This package contains my ELF dynamic linkers (ld-linux.so.1), dynamic
linker library (libdl.so.1) and utilities (ldconfig and ldd) for Linux.
You need Linux kernel 2.0.0 or later with ELF support compiled in
(i.e. not loaded as a module) to use this package.
The dynamic linker is used to bootstrap programs and load shared
libraries at startup. The dynamic linker library is used to
dynamically load shared libraries after a program is running.
Ldconfig is used to automatically update the symbolic links to shared
libraries and build the cache file used by the dynamic linker. Ldd is
used to list the shared libraries used by a program.
Please see the included manual pages for further details.
To install, simply run "sh instldso.sh" as root. Ready-to-go versions
of all end-products are provided so nothing should need to be compiled
or linked. If you are still using libc5 as your primary development
library, you should use the "--devfiles" option when running
instldso.sh to install the file needed to compile with libdl.
ELF versions of gcc, binutils and libc are now required to compile
everything, including the old, unsupported, a.out dynamic linker.
Finally, an optimization level of O2 or higher must be used to compile
ld-linux.so and libdl.so due the use of inline functions.
Notable contributors to this package include Eric Youngdale, Peter
MacDonald, Hongjiu Lu, Linus Torvalds, Lars Wirzenius, Mitch D'Souza,
Rik Faith, Andreas Schwab and Adam Richter (not necessarily in that
order).
###################### IMPORTANT NOTICES #############################
A.OUT SUPPORT:
As of ld.so-1.9.0, the old, a.out dynamic loader is no longer
officially supported. The code is still included and built, but I
make no promises that it will work. I will accept patches for it,
but they will not be tested by me.
GLIBC (AKA LIBC6) SUPPORT:
As of ld.so-1.9.0, the main focus of this package is to ease the
transition to libc6. No significant, new features are expected to be
added. If you need new features, switch to libc6.
Except for libpthread.so, the sonames of the core libraries provided
with libc6 have been chosen so they do not conflict with those
provided by libc5 and ld.so. However, the current plan is not use
new, nonconflicting sonames for other libraries such as ncurses and
X11. This presents two problems. First, libraries using the same
soname for both libc5 and libc6 can not be placed in the same
directory. Second, the dynamic linkers need to make sure not to load
a library for the wrong version of libc.
The first problem is easy. Just move the old, libc5-based libraries
to new directories (e.g. /lib/libc5-compat, /usr/lib/libc5-compat,
etc.) and add those directories to /etc/ld.so.conf. Then install the
new, libc6-based versions in the standard places.
The second problem is more difficult. Ideally, the dynamic linkers
would be changed to perform a complete dependency analysis on every
library to be loaded to make sure the wrong versions aren't used.
This approach doesn't seem worth the added complexity, especially
since we now have symbol versioning for ELF libraries. Instead a
simpler approach will be used, at least initially.
Ldconfig has been modified to perform a (currently simple) dependency
analysis on libraries and to store an indication in /etc/ld.so.cache
of whether a library is for libc5, libc6 or an unknown libc. The
dynamic linkers then only need to make a simple check at run-time to
make sure they don't load the wrong version of a library.
The dynamic linker for libc5 provided in this package, has already
been modified to use the new information in /etc/ld.so.cache. For
glibc versions 2.0.1 and earlier, the dynamic linker for libc6 needs
the patch contained in glibc.patch. You should apply the patch and
rebuild glibc before using the new ldconfig.
As stated above, the dependency analysis currently done by ldconfig is
rather simple. Basically, it looks for the sonames used by the
various versions of libc, libm and libdl. For any approach using a
dependency analysis such as this to work, it is very important that
shared libraries be built with complete dependency information. This
can be done by using the appropriate -l options when running 'gcc
-shared'. For example, when building libfoo.so which depends on libc
and libbar, you should add -lbar and -lc gcc command line.
######################################################################
Changes in version 1.9.11:
Fixed a bug in ld-linux.so where a reference to an
undefined symbol could cause a segfault.
Added a clarification for LD_PRELOAD to the ld.so manual
page and added a symlink for ld-linux.so (Bug#33123).
Don't install ldd for Debian except for the m68k arch
because glibc 2.1 now includes it (Bug#35458).
Changes in version 1.9.10:
Changed ldconfig to issue a warning and not overwrite a
regular file with a symlink (Bug#30859).
Changed Debian packaging to conflict with and replace the
ldconfig package (Bug#29398).
Changes in version 1.9.9:
Changed ld-linux.so and libdl.so to match glibc by not
allowing user preloads of system libraries into setu/gid
binaries unless the library itself is setuid.
Fixed problems in ld-linux.so on the sparc architecture
(Juan Cespedes).
Changes in version 1.9.8:
Changed ldconfig to allow the expected type for all
libraries in a directory to be optionally specified
(Mark Phillips). See the ldconfig man page.
Changed ldconfig to use the same type names used in the
change above when the -p option is used.
Changes in version 1.9.7:
Changed ldd for m68k to use /lib/ld.so.1 instead of
/lib/ld-linux.so.2.
Added support for dladdr to libdl.so (Eduard Gode).
Fixed a small memory leak in libdl.so (Richard Garnish).
Fixed a bug in ldconfig when the -l option was used on a
filename without a '/' in it.
Updated the man pages (Bug#6404, Bug#9721, Bug#10652,
Bug#13494 and Bug#14127). They could still use some work.
No longer install the info page since it's way out of date.
Fixed minor Debian packaging problems (Bug#13160,
Bug#15577 and Bug#19345).
Changes in version 1.9.6:
Changed ldd to not use the glibc dynamic linker when run
on a libc5-based shared library.
Added a -q option to ldconfig which causes warnings not
to be printed (Bob Tinsley).
Dropped support for the Debian libdl1-dev package.
Changed ld-linux.so to be compilable with gcc 2.8.0 (Sven
Verdoolaege)
Changes in version 1.9.5:
Fixed a bug in ldd where ld-linux.so.2 was not called
correctly when run on shared libraries.
Fixed a problem in the previous version where some
Makefiles were not architecture independent.
Changes in version 1.9.4:
Fixed a bug in ld.so introduced in the previous version
which broke preloads.
Turned a.out support back on by default, at least for the
time being. There are no promises to keep it.
Changes in version 1.9.3:
Fixed buffer overflow bugs in ld-linux.so and ld.so.
Changed the README file a little to clarify a couple of
things.
Changed ldconfig to chroot to the specified directory when
the new -r option is used (Bob Tinsley).
Changes in version 1.9.2:
Removed /usr/local/lib from the default /etc/ld.so.conf
for Debian (Bug#8181).
Changed ldconfig to be 64-bit clean (H.J. Lu).
Changes in version 1.9.1:
Changed ldconfig to try to determine which libc a
library is for even if it doesn't have an soname.
Fixed a bug in ldconfig where an older library using
the glibc naming convention would be used instead of
a newer library.
Changed to ld-linux.so and libdl.so to not require the
libc5 headers in order to compile.
Changed ldconfig and ldd to be compilable with either
libc5 or libc6.
Changes in version 1.9.0:
Changed to not build the old, a.out dynamic loader by
default.
Changed instldso.sh to require the --force option to
make sure users read the README file.
Changed instldso.sh to not install the libdl.so
development files unless the --devfiles option is used.
Changed instldso.sh to not strip binaries and libraries
if the --no-strip option is used.
Changed the Debian packaging to put the development files
which conflict with glibc in a new libdl1-dev package.
Changed ldd to use the glibc dynamic linker, if it is
available, when run on a shared library.
Changed ld-linux.so to print the load addresses of
libraries, ala glibc, when run by ldd.
Changed ld-linux.so to allow the libraries listed in
LD_PRELOAD to be separated by white space in addition to
colons.
Changed ld-linux.so to load the libraries listed in
LD_PRELOAD for setu/gid programs as long as they can be
loaded securely.
Changed ldconfig to update the symlinks for the dynamic
linkers.
Changed ldconfig to try to determine if an ELF library is
intended for libc5 or libc6 and save the infomation in the
cache. The mechanism used is rather simplistic and may
need to be enhanced.
Changed ldconfig to print the type of ELF library when
printing the cache.
Changed ld-linux.so to only load ELF shared libraries for
use with libc5 or an unknown libc.
Changes in version 1.8.10:
Fixed a bug in ldconfig where a symlink could be used
instead of a regular file.
Fixed a Debian packaging problem for the sparc
architecture.
Changes in version 1.8.9:
Changed ldconfig to only cache the symlinks it creates.
This make the behavior of the dynamic linkers consistent
with how they would behave if a cache was not used.
Changed ldconfig to cache the symlinks that it finds but
use the name of the symlink as the soname instead of the
actual soname.
Changes in version 1.8.8:
Minor documentation updates to reflect recent changes.
Changed ld.so and ld-linux.so to perform more complete
validation on ld.so.cache before using it.
Changed ldconfig to accept libraries with inconsistent
sonames since glibc is going to use them. A warning is
still printed in debug mode.
Changed the install script to not strip _dl_debug_state
from ld-linux.so since gdb needs it.
More sparc fixes (Derrick Brashear).
Changed ldconfig to not issue a warning when a linker
script disguised as a shared library is found.
Fixed a bug in ld-linux.so where some registers were
not preserved on the first call to a function causing
problems for non-C-like languages (Tim Renouf).
Fixed a bug in ld-linux.so where global variables were
not always mapped correctly across dynamically loaded
libraries (Mikihiko Nakao).
Converted to new Debian source packaging format (Shaya
Potter).
Changes in version 1.8.6/7:
Never released as some unofficial patches used these
version numbers.
Changes in version 1.8.5:
Fixed a bug in ld.so introduced in the previous changes.
Changes in version 1.8.4:
Changed ldconfig to completely ignore symbolic links.
Changed ldconfig to issue the warning concerning an
inconsistent soname in non-verbose mode.
Changed ld-linux.so back to not keep ld.so.cache mapped
at all times.
Changed Debian packaging to compress man pages, strip all
binaries (Bug#5125) and include a shlibs file.
Changes in version 1.8.3:
Changed ld-linux.so to process LD_PRELOAD before
/etc/ld.so.preload.
Fixed a Debian packaging problem where libdl might not
be available if other packages were upgraded at the same
time (Debian Bug#4728).
Changed ldd to always exit with status 1 if any errors
occur (Debian Bug#4188).
Fixed some minor problems in instldso.sh (Mike Castle and
Wolfgang Franke).
Changed ldconfig to issue a warning in verbose mode when
skipping a library because the soname doesn't match.
More sparc fixes (Miguel de Icaza).
Don't link with -N when building ld.so (Alan Modra).
Changed ld-linux.so to better support position-dependant
libraries (NIIBE Yutaka).
Changes in version 1.8.2:
Added a texinfo file for ld.so and libdl (Michael
Deutschmann).
Minor sparc and installation changes (Elliot Lee).
Added multiple architecture support for Debian (Leland
Lucius).
Changed libdl to better support RTLD_NEXT (Eric
Youngdale). Note: the exact meaning of ETLD_NEXT is
still not clear in all cases.
Removed some libc dependencies from libdl. Still need
to remove malloc and free.
Changes in version 1.8.1:
Changed ld.so to be compiled as ELF. This also means
that ELF support is now required. A.out support is
still optional.
Changed ld-linux.so and libdl.so to use the rpath in the
executable instead of in the invoking shared library.
More m68k fixes (Andreas Schwab).
Various sparc fixes (Miguel de Icaza).
Changed ldcnnfig to ignore libraries ending in '~'.
Changed ldconfig to allow alternative conf and cache
files to be specified on the command-line.
Changed libdl.so to work when dlsym is passed a NULL
handle pointer.
Changes in version 1.8.0:
Changed ld-linux.so to be more liberal when checking to
see if a library is already loaded. This should avoid
the duplicate loading problem for programs linkeed with
the -rpath option.
Various m68k fixes (Andreas Schwab).
Changed ld.so to only use LD_AOUT_LIBRARY_PATH and
LD_AOUT_PRELOAD and ld-linux.so to only use
LD_LIBRARY_PATH and LD_PRELOAD. LD_ELF_LIBRARY_PATH
and LD_ELF_PRELOAD are no longer supported.
Changed ld-linux.so to allow debugging of shared and
dynamically loaded libraries (H.J. Lu, Andreas Schwab).
Changed ld-linux.so to preload ELF shared libraries
listed in /etc/ld.so.preload. This allows secure
preloads, even for setuid/setgid programs.
Changed ld-linux.so to keep ld.so.cache mapped at all
times.
Changed ldconfig to allow #-style comments in ld.so.conf.
Removed various compiler warnings (Richard Sladkey and
David Engel).
Changed ldd to work on ELF shared libraries. This may
need a little more work.
Changes in version 1.7.14:
Changed ldconfig to recognize ELF shared libraries
generated by post-2.6 versions of ld (Andreas Schwab).
Changed ldconfig to not remove stale links that do not
have a version number since they may be needed by ld.
Changes in version 1.7.13:
Fixed a problem in ld-linux.so where a program linked
with a shared library that was not used could result in
a segmentation fault (H.J. Lu).
Changes in version 1.7.12:
Fixed a problem in libdl.so where the wrong library
could be marked as global when RTLD_GLOBAL was used
(Lars Heete).
Installed dlfcn.h with libdl.so instead of requiring
it to be supplied with libc.
Removed support for libldso.a since it was nearly
impossible to use anyway.
Changed ldd to detect when the program being checked
exited abnormally.
Changes in version 1.7.11:
Changed ld.so and ld-linux.so to delete all variations
of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs,
This makes it harder for broken set[ug]id programs to be
compromised.
Fixed a problem in libdl.so where dlsym would not accept
the handle returned from dlopen(0, *).
Changes in version 1.7.10:
Changed ld-linux.so and libdl.so to support RTLD_GLOBAL
(Eric Youngdale).
Changes in version 1.7.9:
Fixed a problem in ld-linux.so in detecting when the
new user/group information is provided by the kernel.
Fixed a problem in ld-linux.so where a buffer could be
overflowed if a large number of libraries were loaded
(Thomas Moore).
Changes in version 1.7.8:
Changed the Makefiles and install scripts to support
a.out- and ELF-only configurations.
Changed ld-linux.so to use the user/group information
provided by linux 1.3.23+ instead of making syscalls
to get it.
Changed libdl.so to support RTLD_NEXT (Glenn Fowler).
Changed libdl.so to only execute the fini sections
instead of completely closing libraries at exit (Glenn
Fowler).
Changed ld.so and ld-linux.so to print the required
cache version when a mismatch is detected.
Changed ld-linux.so to not require on /dev/zero (Ralph
Loader).
Minor m68k cleanups (Andreas Schwab).
Changes in version 1.7.7:
Fixed problems compiling with recent 1.3.x kernels.
Changed ld-linux.so to not use MAP_DENYWRITE until the
permission issue regarding it is resolved.
Changes in version 1.7.6:
Fixed a bug in ld-linux.so dealing with a zero-length
LD_{ELF_}PRELOAD.
Changed ld.so and ld-linux.so to truncate all variations
of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs.
Changes in version 1.7.5:
Changed ldconfig to recognize libraries without any
version number (eg. libXYZ.so).
Changed ldconfig to not generate a corrupt cache when
the disk is full or other write errors occur.
Changed ld-linux.so to map files with MAP_DENYWRITE to
keep them from being changed while the file is in use
(Rick Sladkey).
Changed libdl to not overwrite the scope pointer of a
library if it was already loaded (H.J. Lu).
Changed ld-linux.so so gdb can be used on constructors
(Eric Youngdale).
Changed ldconfig to ignore ELF libraries where the soname
does not match the file name on the assumption that it is
a used at compile-time (eg. libcurses.so -> libncruses.so).
Changes in version 1.7.4:
Changed ld-linux.so and libdl to use the appropriate
rpaths when searching for shared libraries (Eric
Youngdale).
Changed ld-linux.so to search rpath before using the
cache. This more closely conforms to the IBCS standard.
Changes in version 1.7.3:
Changed ld-linux.so to only print a library name the
first time it is loaded when run from ldd.
Fixed a bug in ldconfig where an invalid cache could be
generated if a directory was specified multiple times in
ld.so.conf.
Changed ld-linux.so so it will return the address of a
weak symbol when called from dlsym in libdl (Eric
Youngdale.
Changes in version 1.7.2:
Changed libdl.so again to fix the undefined foobar
problem.
Changes in version 1.7.1:
Changed libdl so it will compile at optimization level
O3 or higher.
Changed ldconfig to always create the cache file with
mode 644.
Changed ldconfig to not ingore valid symlinks.
Changed ldconfig to use the library name as the soname
for ELF libraries that do not have an soname entry.
Changed ld-linux.so to print the actual, requested library
name at the time it is loaded instead of trying to figure
it out after the fact.
Changes in version 1.7.0:
Changed ldconfig to read the actual soname from the image
for ELF libraries and make it available to ld-linux.so.
The soname for DLL libraries is still determined by
truncating the minor numbers from the image file name.
Changed ldconfig to no longer support the undocumented
sort options.
Changed ld.so to require a valid cache to find libraries
in directories specified in ld.so.conf. /usr/lib and /lib
are still searched as a last resort. Ld-linux.so already
operated this way.
Fixed a bug in libldso.a where the arguments to
shared_loader were not parsed correctly (Wolfram Gloger).
Added support for RELA-style relocations under Linux/68k
(Andreas Schwab).
Changed ld-linux.so to only map the cache once for all
libraries instead of individually for each library.
Changed ld-linux.so continue searching the cache instead of
giving up when failing to load the first entry found.
Changed ld-linux.so to produce output similar to ld.so when
run from ldd or when errors occur.
Changes in version 1.6.7:
Changed the install scripts to make sure that ld.so and
ld-linux.so are always usable.
Added support for Linux/Sparc (Eric Youngdale).
Added support for Linux/68k (Andreas Schwab).
Fixed various bugs in ld-linux.so dealing with closing
files, unmapping memory, dereferencing NULL pointers and
printing library names (David Engel, Eric Youngdale and
Andreas Schwab).
Replaced the manual page for libdl with a freely
distributable one (Adam Richter).
Fixed a bug in ld-linux.so where LD_LIBRARY_PATH and
LD_PRELOAD were not cleared for setuid/setgid programs.
Fixed a bug in libdl where dlsym would not return the
correct address of a symbol if it was redefined in another
library (Oleg Kibirev).
Changed ld-linux.so to use the following order to search
for libraries: LD_{ELF_}LIBRARY_PATH, ld.so.cache, rpath,
/usr/lib and /lib.
Changed ld-linux.so to not needlessly allocate memory when
using ld.so.cache.
Changes in version 1.6.6:
Changed ldconfig to not warn about removing stale links
unless the -v option is specified.
Added manual pages for libdl (from FreeBSD/Sun)
Fixed a bug in ld.so dealing with preloading of objects
generated by recent versions of ld (Mitch D'Souza).
Fixed bugs in ldd where some errors were either not
detected or not printed.
Fixed a bug in ld-linux.so where the trailing nul in a
library name was not being copied (Owen Taylor).
Changes in version 1.6.5:
Changed ldconfig to remove stale symbolic links.
Added debug hooks in ld-linux.so and libdl.so to be used
by a future version of gdb (Eric Youngdale).
Changes in version 1.6.4:
Change ld-linux.so to print on stdout instead of stderr
when run from ldd.
Added support for Debian GNU/Linux packaging.
Changes in version 1.6.3:
Fixed a bug in libdl when closing a library (H.J. Lu).
Changes in version 1.6.2:
Changed the error message printed by ldd when a file is
not a.out or ELF. It used to only list a.out formats.
Changed ldconfig to no longer cache and set up links for
ld-linux.so.
Changed ld-linux.so and libdl to not conflict with upcoming
changes in kernel header files.
Changed ld-linux.so to not print preloaded libraries.
Changes in version 1.6.1:
Updated the installation script.
Changed ld.so and ld-linux.so to look for LD_AOUT_PRELOAD
and LD_ELF_PRELOAD, respectively, before LD_PRELOAD.
Changed ld.so and ld-linux.so to use LD_AOUT_LIBRARY_PATH
and LD_ELF_LIBRARY_PATH, respectively, instead of
AOUT_LD_LIBRARY_PATH and ELF_LD_LIBRARY_PATH.
Changes in version 1.6.0:
Changed ldconfig to process libraries which do not have
a minor version or patch level number.
Incorporated ld-linux.so and libdl.so.
Changed ld.so and ld-linux.so to not miss entries in the
cache when the fully qualified library is requested.
Changed ldconfig to use stdout instead of stderr when
printing the cache.
Changes in version 1.5.3:
LD_PRELOAD enhancements (Tristan Gigold).
LD_PRELOAD patch for linux-68k (Andreas Schwab).
Changes in version 1.5.2:
More ELF changes (Mitch D'Souza).
Changed ldconfig to also update the link for ld-linux.so.
Changes in version 1.5.1:
More ELF and LD_PRELOAD changes (Mitch D'Souza).
Changes in version 1.5.0:
Chnaged all executables to QMAGIC (Mitch D'Souza and Rick
Sladkey).
Added preliminary support for ELF to ldd and ldconfig (Eric
Youndale and H.J. Lu).
Added support for LD_PRELOAD to ld.so (Mitch D'Souza).
Removed the "advertising" clause from the copyright notices
in all source files.
Changes in version 1.4.4:
Changed ldconfig to support QMAGIC libraries.
Fixed a bug in ld.so where some of the error messages had
transposed arguments.
Changes in version 1.4.3:
Fixed an obscure bug in ld.so where an index was not being
incremented when a library was not found using the cache.
Changes in version 1.4.2:
Changed ldconfig to issue a warning and continue instead
of an error and exiting when a link can't be updated.
This is useful when some libraries are imported on read-
only file systems, such as an NFS mounted /usr.
Changed ld.so to be more robust in searching for libraries.
A library is not considered found unless it can actually be
loaded. If a library is not found using the cache, the
standard directories are searched as in pre-cache versions.
Changes in version 1.4.1:
Fixed minor Makefile problems.
Added support for linux-68k.
Fixed a bug in ld.so where libraries with absolute paths
were not handled correctly.
Changed ld.so to ignore the directory in the names of
shared libraries by default. This allows older libraries
with absolute paths, such as the XView libraries, to take
advantage of the cache support.
Added a minimal usage message to ldconfig.
Changes in version 1.4:
Fixed bug in ld.so where minor version numbers were not
reported correctly when a minor version incompatibility
was found.
Fixed bug in ldconfig where libraries with subversion
numbers greater than 9 were not compared correctly.
Added Mitch D'Souza's support for suppressing warning
messages from ld.so about minor version incompatibilities.
Added Mitch D'Souza's support for using a cache to speed
up searching for libraries in the standard directories.
Added Mitch D'Souza's support for a debugging version of
ld.so. Link with -lldso if you think you are experiencing
dynamic linker problems.
Changes in version 1.3:
Added support for libraries using absolute pathnames. If I
had known that the XView libraries used them, I would have
added this earlier.
Fixed a bug handling old libraries using a pathname beginning
with '/' or '/lib/'.
Changes in version 1.2a:
Fixed a minor bug in ldd which caused all files, specifically
scripts, to be recognized as binaries. Thanks to Olaf Flebbe
for reporting it.
David Engel
david@sw.ods.com

59
ldso/config.h Normal file
View File

@@ -0,0 +1,59 @@
#ifdef DEBUG
# define LDSO_IMAGE "../ld-so/ld.so"
# define LDSO_CONF "../util/ld.so.conf"
# define LDSO_CACHE "../util/ld.so.cache"
# define LDSO_PRELOAD "../util/ld.so.preload"
# define LDDSTUB "../util/lddstub"
#elif UCLIBC_DEVEL
# define LDSO_IMAGE UCLIBC_INSTALL_DIR"/lib/ld.so"
# define LDSO_CONF UCLIBC_INSTALL_DIR"/etc/ld.so.conf"
# define LDSO_CACHE UCLIBC_INSTALL_DIR"/etc/ld.so.cache"
# define LDSO_PRELOAD UCLIBC_INSTALL_DIR"/etc/ld.so.preload"
# define LDDSTUB UCLIBC_INSTALL_DIR"/lib/lddstub"
#else
# define LDSO_IMAGE "/lib/ld.so"
# define LDSO_CONF "/etc/ld.so.conf"
# define LDSO_CACHE "/etc/ld.so.cache"
# define LDSO_PRELOAD "/etc/ld.so.preload"
# define LDDSTUB "/usr/lib/lddstub"
#endif
#define LDD_ARGV0 "__LDD_ARGV0"
#define DIR_SEP ":, \t\n"
#define MAX_DIRS 32
typedef void (*loadptr)(int func, ...);
typedef void (*callbackptr)(int ver, int nlibs, char **libs,
int nmods, char **mods);
#define CALLBACK_VER 1
#define LIB_ANY -1
#define LIB_DLL 0
#define LIB_ELF 1
#define LIB_ELF_LIBC5 2
#define LIB_ELF_LIBC6 3
#define LIB_ELF64 0x80
#define FUNC_VERS 0
#define FUNC_LDD 1
#define FUNC_LINK 2
#define FUNC_LINK_AND_CALLBACK 3
#define LDSO_CACHE_MAGIC "ld.so-"
#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
#define LDSO_CACHE_VER "1.7.0"
#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
typedef struct {
char magic [LDSO_CACHE_MAGIC_LEN];
char version [LDSO_CACHE_VER_LEN];
int nlibs;
} header_t;
typedef struct {
int flags;
int sooffset;
int liboffset;
} libentry_t;

39
ldso/ldso/Makefile Normal file
View File

@@ -0,0 +1,39 @@
TOPDIR=../../
include $(TOPDIR)Rules.mak
include $(TOPDIR)/ld.so-1/Config.mk
DIRS = $(TARGET_ARCH) libdl
CFLAGS += -DNO_UNDERSCORE -DVERBOSE_DLINKER
CFLAGS += -DUSE_CACHE #-fPIC -D__PIC__ #-funroll-loops
CSRC= boot1.c hash.c readelflib1.c vsprintf.c
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
DLINKER = ld-linux-uclibc.so
ELF_LDFLAGS=--shared # using GNU ld
ifneq ($(DIRS),)
lib realclean clean::
@set -e; for i in $(DIRS); do \
echo making $@ in $$i; \
$(MAKE) -C $$i $@; \
done;
endif
lib:: $(OBJS)
$(LD) -e _dl_boot $(ELF_LDFLAGS) -o $(DLINKER).$(LDSO_VMAJOR) \
-soname $(DLINKER).$(LDSO_VMAJOR) *.o
$(COBJS): %.o : %.c
$(CC) -I. -I./$(TARGET_ARCH) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
realclean::
$(RM) -f .depend $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~
clean::
$(RM) -f $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~

1005
ldso/ldso/boot1.c Normal file

File diff suppressed because it is too large Load Diff

588
ldso/ldso/dl-elf.c Normal file
View File

@@ -0,0 +1,588 @@
/* Load an ELF sharable library into memory.
Copyright (C) 1993-1996, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file contains the helper routines to load an ELF sharable
library into memory and add the symbol table info to the chain. */
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include "string.h"
/*#include <stdlib.h>*/
#include <linux/mman.h>
#include <linux/stat.h>
#include "hash.h"
#include "linuxelf.h"
#include "sysdep.h"
#include <linux/unistd.h>
#include "syscall.h"
#ifdef USE_CACHE
#include "../config.h"
#endif
extern char *_dl_progname;
#ifdef USE_CACHE
static caddr_t _dl_cache_addr = NULL;
static size_t _dl_cache_size = 0;
int _dl_map_cache(void)
{
int fd;
struct kernel_stat st;
header_t *header;
libentry_t *libent;
int i, strtabsize;
if (_dl_cache_addr == (caddr_t)-1)
return -1;
else if (_dl_cache_addr != NULL)
return 0;
if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
{
_dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
_dl_cache_addr = (caddr_t)-1; /* so we won't try again */
return -1;
}
_dl_cache_size = st.st_size;
_dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
MAP_SHARED, fd, 0);
_dl_close (fd);
if (_dl_cache_addr == (caddr_t)-1)
{
_dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
return -1;
}
header = (header_t *)_dl_cache_addr;
if (_dl_cache_size < sizeof (header_t) ||
_dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
_dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
_dl_cache_size <
(sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
_dl_cache_addr[_dl_cache_size-1] != '\0')
{
_dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
goto fail;
}
strtabsize = _dl_cache_size - sizeof (header_t) -
header->nlibs * sizeof (libentry_t);
libent = (libentry_t *)&header[1];
for (i = 0; i < header->nlibs; i++)
{
if (libent[i].sooffset >= strtabsize ||
libent[i].liboffset >= strtabsize)
{
_dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
goto fail;
}
}
return 0;
fail:
_dl_munmap(_dl_cache_addr, _dl_cache_size);
_dl_cache_addr = (caddr_t)-1;
return -1;
}
int _dl_unmap_cache(void)
{
if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
return -1;
#if 1
_dl_munmap (_dl_cache_addr, _dl_cache_size);
_dl_cache_addr = NULL;
#endif
return 0;
}
#endif
/*
* Used to return error codes back to dlopen et. al.
*/
unsigned int _dl_error_number;
unsigned int _dl_internal_error_number;
struct elf_resolve * _dl_load_shared_library(int secure,
struct elf_resolve * tpnt, char * full_libname) {
char * pnt, *pnt1, *pnt2;
struct elf_resolve *tpnt1 = NULL;
char mylibname[2050];
char * libname;
_dl_internal_error_number = 0;
/* quick hack to ensure mylibname buffer doesn't overflow. don't
allow full_libname or any directory to be longer than 1024. */
if (_dl_strlen(full_libname) > 1024)
goto goof;
pnt = libname = full_libname;
while (*pnt) {
if(*pnt == '/') libname = pnt+1;
pnt++;
}
/* If the filename has any '/', try it straight and leave it at that.
For IBCS2 compatibility under linux, we substitute the string
/usr/i486-sysv4/lib for /usr/lib in library names. */
if (libname != full_libname) {
tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
if (tpnt1)
return tpnt1;
goto goof;
}
/*
* The ABI specifies that RPATH is searched before LD_*_PATH or
* the default path of /usr/lib.
* Check in rpath directories
*/
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
if (tpnt->libtype == elf_executable) {
pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
if(pnt1) {
pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
while(*pnt1){
pnt2 = mylibname;
while(*pnt1 && *pnt1 != ':') {
if (pnt2 - mylibname < 1024)
*pnt2++ = *pnt1++;
else
pnt1++;
}
if (pnt2 - mylibname >= 1024)
break;
if(pnt2[-1] != '/') *pnt2++ = '/';
pnt = libname;
while(*pnt) *pnt2++ = *pnt++;
*pnt2++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if(tpnt1) return tpnt1;
if(*pnt1 == ':') pnt1++;
}
}
}
}
/* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
pnt1 = _dl_library_path;
if (pnt1 && *pnt1) {
while (*pnt1) {
pnt2 = mylibname;
while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
if (pnt2 - mylibname < 1024)
*pnt2++ = *pnt1++;
else
pnt1++;
}
if (pnt2 - mylibname >= 1024)
break;
if(pnt2[-1] != '/') *pnt2++ = '/';
pnt = libname;
while(*pnt) *pnt2++ = *pnt++;
*pnt2++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if(tpnt1) return tpnt1;
if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
}
}
/*
* Where should the cache be searched? There is no such concept in the
* ABI, so we have some flexibility here. For now, search it before
* the default path of /usr/lib.
*/
#ifdef USE_CACHE
if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
{
int i;
header_t *header = (header_t *)_dl_cache_addr;
libentry_t *libent = (libentry_t *)&header[1];
char *strs = (char *)&libent[header->nlibs];
for (i = 0; i < header->nlibs; i++)
{
if ((libent[i].flags == LIB_ELF ||
libent[i].flags == LIB_ELF_LIBC5) &&
_dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
(tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
return tpnt1;
}
}
#endif
#ifdef UCLIBC_DEVEL
/* Check in /usr/<arch>-linux-uclibc/lib */
pnt1 = UCLIBC_INSTALL_DIR"/lib";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
#else /* UCLIBC_DEVEL */
/* Check in /usr/lib */
pnt1 = "/usr/lib/";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
/* Check in /lib */
/* try "/lib/". */
pnt1 = "/lib/";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
#endif /* UCLIBC_DEVEL */
goof:
/* Well, we shot our wad on that one. All we can do now is punt */
if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
else _dl_error_number = DL_ERROR_NOFILE;
return NULL;
}
/*
* Read one ELF library into memory, mmap it into the correct locations and
* add the symbol info to the symbol chain. Perform any relocations that
* are required.
*/
//extern _elf_rtbndr(void);
struct elf_resolve * _dl_load_elf_shared_library(int secure,
char * libname, int flag) {
struct elfhdr * epnt;
unsigned int dynamic_addr = 0;
unsigned int dynamic_size = 0;
struct dynamic * dpnt;
struct elf_resolve * tpnt;
struct elf_phdr * ppnt;
int piclib;
char * status;
int flags;
char header[4096];
int dynamic_info[24];
int * lpnt;
unsigned int libaddr;
unsigned int minvma=0xffffffff, maxvma=0;
int i;
int infile;
/* If this file is already loaded, skip this step */
tpnt = _dl_check_hashed_files(libname);
if(tpnt) return tpnt;
/* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
we don't load the library if it isn't setuid. */
if (secure) {
struct kernel_stat st;
if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
return NULL;
}
libaddr = 0;
infile = _dl_open(libname, O_RDONLY);
if(infile < 0)
{
#if 0
/*
* NO! When we open shared libraries we may search several paths.
* it is inappropriate to generate an error here.
*/
_dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
#endif
_dl_internal_error_number = DL_ERROR_NOFILE;
return NULL;
}
_dl_read(infile, header, sizeof(header));
epnt = (struct elfhdr *) header;
if (epnt->e_ident[0] != 0x7f ||
epnt->e_ident[1] != 'E' ||
epnt->e_ident[2] != 'L' ||
epnt->e_ident[3] != 'F') {
_dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_NOTELF;
_dl_close(infile);
return NULL;
};
if((epnt->e_type != ET_DYN) ||
(epnt->e_machine != MAGIC1
#ifdef MAGIC2
&& epnt->e_machine != MAGIC2
#endif
)){
_dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
_dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
_dl_progname, libname);
_dl_close(infile);
return NULL;
};
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
piclib = 1;
for(i=0;i < epnt->e_phnum; i++){
if(ppnt->p_type == PT_DYNAMIC) {
if (dynamic_addr)
_dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
_dl_progname, libname);
dynamic_addr = ppnt->p_vaddr;
dynamic_size = ppnt->p_filesz;
};
if(ppnt->p_type == PT_LOAD) {
/* See if this is a PIC library. */
if(i == 0 && ppnt->p_vaddr > 0x1000000) {
piclib = 0;
minvma=ppnt->p_vaddr;
}
if(piclib && ppnt->p_vaddr < minvma) {
minvma = ppnt->p_vaddr;
}
if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
maxvma = ppnt->p_vaddr + ppnt->p_memsz;
}
}
ppnt++;
};
maxvma=(maxvma+0xfffU)&~0xfffU;
minvma=minvma&~0xffffU;
flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
if(!piclib) flags |= MAP_FIXED;
status = (char *) _dl_mmap((char *) (piclib?0:minvma),
maxvma-minvma,
PROT_NONE,
flags | MAP_ANONYMOUS, -1,
0);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_close(infile);
return NULL;
};
libaddr=(unsigned int)status;
flags|=MAP_FIXED;
/* Get the memory to store the library */
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
for(i=0;i < epnt->e_phnum; i++){
if(ppnt->p_type == PT_LOAD) {
/* See if this is a PIC library. */
if(i == 0 && ppnt->p_vaddr > 0x1000000) {
piclib = 0;
/* flags |= MAP_FIXED; */
}
if(ppnt->p_flags & PF_W) {
unsigned int map_size;
char * cpnt;
status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) +
(ppnt->p_vaddr & 0xfffff000)),
(ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
LXFLAGS(ppnt->p_flags),
flags, infile,
ppnt->p_offset & 0x7ffff000);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_munmap((char *)libaddr, maxvma-minvma);
_dl_close(infile);
return NULL;
};
/* Pad the last page with zeroes. */
cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
/* I am not quite sure if this is completely correct to do or not, but
the basic way that we handle bss segments is that we mmap /dev/zero if
there are any pages left over that are not mapped as part of the file */
map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0),
ppnt->p_vaddr + ppnt->p_memsz - map_size,
LXFLAGS(ppnt->p_flags),
flags | MAP_ANONYMOUS, -1, 0);
} else
status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) +
(piclib?libaddr:0),
(ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
LXFLAGS(ppnt->p_flags),
flags, infile,
ppnt->p_offset & 0x7ffff000);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_munmap((char *)libaddr, maxvma-minvma);
_dl_close(infile);
return NULL;
};
/* if(libaddr == 0 && piclib) {
libaddr = (unsigned int) status;
flags |= MAP_FIXED;
}; */
};
ppnt++;
};
_dl_close(infile);
/* For a non-PIC library, the addresses are all absolute */
if(piclib) {
dynamic_addr += (unsigned int) libaddr;
}
/*
* OK, the ELF library is now loaded into VM in the correct locations
* The next step is to go through and do the dynamic linking (if needed).
*/
/* Start by scanning the dynamic section to get all of the pointers */
if(!dynamic_addr) {
_dl_internal_error_number = DL_ERROR_NODYNAMIC;
_dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
return NULL;
}
dpnt = (struct dynamic *) dynamic_addr;
dynamic_size = dynamic_size / sizeof(struct dynamic);
_dl_memset(dynamic_info, 0, sizeof(dynamic_info));
for(i=0; i< dynamic_size; i++){
if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
if(dpnt->d_tag == DT_TEXTREL ||
SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
dpnt++;
};
/* If the TEXTREL is set, this means that we need to make the pages
writable before we perform relocations. Do this now. They get set back
again later. */
if (dynamic_info[DT_TEXTREL]) {
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
for(i=0;i < epnt->e_phnum; i++, ppnt++){
if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
_dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
(ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
PROT_READ | PROT_WRITE | PROT_EXEC);
}
}
tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr,
dynamic_size);
tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
tpnt->n_phent = epnt->e_phnum;
/*
* OK, the next thing we need to do is to insert the dynamic linker into
* the proper entry in the GOT so that the PLT symbols can be properly
* resolved.
*/
lpnt = (int *) dynamic_info[DT_PLTGOT];
if(lpnt) {
lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
INIT_GOT(lpnt, tpnt);
};
return tpnt;
}
/* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY
relocations for global variables that are present both in the image and
the shared library. Go through and do it manually. If the images
are guaranteed to be generated by a trustworthy linker, then this
step can be skipped. */
int _dl_copy_fixups(struct dyn_elf * rpnt)
{
int goof = 0;
struct elf_resolve * tpnt;
if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
else return 0;
tpnt = rpnt->dyn;
if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
tpnt->init_flag |= COPY_RELOCS_DONE;
#ifdef ELF_USES_RELOCA
goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
tpnt->dynamic_info[DT_RELASZ], 0);
#else
goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
tpnt->dynamic_info[DT_RELSZ], 0);
#endif
return goof;
}

284
ldso/ldso/dl-hash.c Normal file
View File

@@ -0,0 +1,284 @@
/* Run an ELF binary on a linux system.
Copyright (C) 1993-1996, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Various symbol table handling functions, including symbol lookup */
/*#include <stdlib.h>*/
#include "string.h"
#include <linux/unistd.h>
#include <linux/elf.h>
#include "libdl/dlfcn.h"
#include "hash.h"
#include "linuxelf.h"
#include "syscall.h"
#include "string.h"
#include "sysdep.h"
/*
* This is the start of the linked list that describes all of the files present
* in the system with pointers to all of the symbol, string, and hash tables,
* as well as all of the other good stuff in the binary.
*/
struct elf_resolve * _dl_loaded_modules = NULL;
/*
* This is the list of modules that are loaded when the image is first
* started. As we add more via dlopen, they get added into other
* chains.
*/
struct dyn_elf * _dl_symbol_tables = NULL;
/*
* This is the list of modules that are loaded via dlopen. We may need
* to search these for RTLD_GLOBAL files.
*/
struct dyn_elf * _dl_handles = NULL;
/*
* This is the hash function that is used by the ELF linker to generate
* the hash table that each executable and library is required to
* have. We need it to decode the hash table.
*/
unsigned long _dl_elf_hash(const char * name){
unsigned long hash = 0;
unsigned long tmp;
while (*name){
hash = (hash << 4) + *name++;
if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
hash &= ~tmp;
};
return hash;
}
/*
* Check to see if a library has already been added to the hash chain.
*/
struct elf_resolve * _dl_check_hashed_files(char * libname){
struct elf_resolve * tpnt;
int len = _dl_strlen(libname);
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
(tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
return tpnt;
}
return NULL;
}
/*
* We call this function when we have just read an ELF library or executable.
* We add the relevant info to the symbol chain, so that we can resolve all
* externals properly.
*/
struct elf_resolve * _dl_add_elf_hash_table(char * libname,
char * loadaddr,
unsigned int * dynamic_info,
unsigned int dynamic_addr,
unsigned int dynamic_size){
unsigned int * hash_addr;
struct elf_resolve * tpnt;
int i;
if (!_dl_loaded_modules) {
tpnt = _dl_loaded_modules =
(struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
_dl_memset (tpnt, 0, sizeof (*tpnt));
}
else {
tpnt = _dl_loaded_modules;
while(tpnt->next) tpnt = tpnt->next;
tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
_dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
tpnt->next->prev = tpnt;
tpnt = tpnt->next;
};
tpnt->next = NULL;
tpnt->init_flag = 0;
tpnt->libname = _dl_strdup(libname);
tpnt->dynamic_addr = dynamic_addr;
tpnt->dynamic_size = dynamic_size;
tpnt->libtype = loaded_file;
if( dynamic_info[DT_HASH] != 0 )
{
hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
tpnt->nbucket = *hash_addr++;
tpnt->nchain = *hash_addr++;
tpnt->elf_buckets = hash_addr;
hash_addr += tpnt->nbucket;
tpnt->chains = hash_addr;
}
tpnt->loadaddr = loadaddr;
for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
return tpnt;
}
/*
* This function resolves externals, and this is either called when we process
* relocations or when we call an entry in the PLT table for the first time.
*/
char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
unsigned int instr_addr, struct elf_resolve * f_tpnt,
int copyrel){
struct elf_resolve * tpnt;
int si;
char * pnt;
int pass;
char * strtab;
struct elf32_sym * symtab;
unsigned int elf_hash_number, hn;
char * weak_result;
struct elf_resolve * first_def;
struct dyn_elf * rpnt, first;
char * data_result = 0; /* nakao */
weak_result = 0;
elf_hash_number = _dl_elf_hash(name);
/* A quick little hack to make sure that any symbol in the executable
will be preferred to one in a shared library. This is necessary so
that any shared library data symbols referenced in the executable
will be seen at the same address by the executable, shared libraries
and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
if(!copyrel && rpnt1) {
first=(*_dl_symbol_tables);
first.next=rpnt1;
rpnt1=(&first);
}
/*
* The passes are so that we can first search the regular symbols
* for whatever module was specified, and then search anything
* loaded with RTLD_GLOBAL. When pass is 1, it means we are just
* starting the first dlopened module, and anything above that
* is just the next one in the chain.
*/
for(pass = 0; (1==1); pass++)
{
/*
* If we are just starting to search for RTLD_GLOBAL, setup
* the pointer for the start of the search.
*/
if( pass == 1) {
rpnt1 = _dl_handles;
}
/*
* Anything after this, we need to skip to the next module.
*/
else if( pass >= 2) {
rpnt1 = rpnt1->next_handle;
}
/*
* Make sure we still have a module, and make sure that this
* module was loaded with RTLD_GLOBAL.
*/
if( pass != 0 )
{
if( rpnt1 == NULL ) break;
if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
}
for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables);
rpnt; rpnt = rpnt->next) {
tpnt = rpnt->dyn;
/*
* The idea here is that if we are using dlsym, we want to
* first search the entire chain loaded from dlopen, and
* return a result from that if we found anything. If this
* fails, then we continue the search into the stuff loaded
* when the image was activated. For normal lookups, we start
* with rpnt == NULL, so we should never hit this.
*/
if( tpnt->libtype == elf_executable
&& weak_result != 0 )
{
break;
}
/*
* Avoid calling .urem here.
*/
do_rem(hn, elf_hash_number, tpnt->nbucket);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] +
tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
/*
* This crap is required because the first instance of a
* symbol on the chain will be used for all symbol references.
* Thus this instance must be resolved to an address that
* contains the actual function,
*/
first_def = NULL;
for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
pnt = strtab + symtab[si].st_name;
if(_dl_strcmp(pnt, name) == 0 &&
(ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
symtab[si].st_value != 0) {
/* Here we make sure that we find a module where the symbol is
* actually defined.
*/
if(f_tpnt) {
if(!first_def) first_def = tpnt;
if(first_def == f_tpnt && symtab[si].st_shndx == 0)
continue;
}
switch(ELF32_ST_BIND(symtab[si].st_info)){
case STB_GLOBAL:
if ( tpnt->libtype != elf_executable
&& ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
break; /* nakao */
} else /* nakao */
return tpnt->loadaddr + symtab[si].st_value;
case STB_WEAK:
if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
break;
default: /* Do local symbols need to be examined? */
break;
}
}
}
}
}
if (data_result) return data_result; /* nakao */
return weak_result;
}

284
ldso/ldso/hash.c Normal file
View File

@@ -0,0 +1,284 @@
/* Run an ELF binary on a linux system.
Copyright (C) 1993-1996, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Various symbol table handling functions, including symbol lookup */
/*#include <stdlib.h>*/
#include "string.h"
#include <linux/unistd.h>
#include <linux/elf.h>
#include "libdl/dlfcn.h"
#include "hash.h"
#include "linuxelf.h"
#include "syscall.h"
#include "string.h"
#include "sysdep.h"
/*
* This is the start of the linked list that describes all of the files present
* in the system with pointers to all of the symbol, string, and hash tables,
* as well as all of the other good stuff in the binary.
*/
struct elf_resolve * _dl_loaded_modules = NULL;
/*
* This is the list of modules that are loaded when the image is first
* started. As we add more via dlopen, they get added into other
* chains.
*/
struct dyn_elf * _dl_symbol_tables = NULL;
/*
* This is the list of modules that are loaded via dlopen. We may need
* to search these for RTLD_GLOBAL files.
*/
struct dyn_elf * _dl_handles = NULL;
/*
* This is the hash function that is used by the ELF linker to generate
* the hash table that each executable and library is required to
* have. We need it to decode the hash table.
*/
unsigned long _dl_elf_hash(const char * name){
unsigned long hash = 0;
unsigned long tmp;
while (*name){
hash = (hash << 4) + *name++;
if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
hash &= ~tmp;
};
return hash;
}
/*
* Check to see if a library has already been added to the hash chain.
*/
struct elf_resolve * _dl_check_hashed_files(char * libname){
struct elf_resolve * tpnt;
int len = _dl_strlen(libname);
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
(tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
return tpnt;
}
return NULL;
}
/*
* We call this function when we have just read an ELF library or executable.
* We add the relevant info to the symbol chain, so that we can resolve all
* externals properly.
*/
struct elf_resolve * _dl_add_elf_hash_table(char * libname,
char * loadaddr,
unsigned int * dynamic_info,
unsigned int dynamic_addr,
unsigned int dynamic_size){
unsigned int * hash_addr;
struct elf_resolve * tpnt;
int i;
if (!_dl_loaded_modules) {
tpnt = _dl_loaded_modules =
(struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
_dl_memset (tpnt, 0, sizeof (*tpnt));
}
else {
tpnt = _dl_loaded_modules;
while(tpnt->next) tpnt = tpnt->next;
tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
_dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
tpnt->next->prev = tpnt;
tpnt = tpnt->next;
};
tpnt->next = NULL;
tpnt->init_flag = 0;
tpnt->libname = _dl_strdup(libname);
tpnt->dynamic_addr = dynamic_addr;
tpnt->dynamic_size = dynamic_size;
tpnt->libtype = loaded_file;
if( dynamic_info[DT_HASH] != 0 )
{
hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
tpnt->nbucket = *hash_addr++;
tpnt->nchain = *hash_addr++;
tpnt->elf_buckets = hash_addr;
hash_addr += tpnt->nbucket;
tpnt->chains = hash_addr;
}
tpnt->loadaddr = loadaddr;
for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
return tpnt;
}
/*
* This function resolves externals, and this is either called when we process
* relocations or when we call an entry in the PLT table for the first time.
*/
char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
unsigned int instr_addr, struct elf_resolve * f_tpnt,
int copyrel){
struct elf_resolve * tpnt;
int si;
char * pnt;
int pass;
char * strtab;
struct elf32_sym * symtab;
unsigned int elf_hash_number, hn;
char * weak_result;
struct elf_resolve * first_def;
struct dyn_elf * rpnt, first;
char * data_result = 0; /* nakao */
weak_result = 0;
elf_hash_number = _dl_elf_hash(name);
/* A quick little hack to make sure that any symbol in the executable
will be preferred to one in a shared library. This is necessary so
that any shared library data symbols referenced in the executable
will be seen at the same address by the executable, shared libraries
and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
if(!copyrel && rpnt1) {
first=(*_dl_symbol_tables);
first.next=rpnt1;
rpnt1=(&first);
}
/*
* The passes are so that we can first search the regular symbols
* for whatever module was specified, and then search anything
* loaded with RTLD_GLOBAL. When pass is 1, it means we are just
* starting the first dlopened module, and anything above that
* is just the next one in the chain.
*/
for(pass = 0; (1==1); pass++)
{
/*
* If we are just starting to search for RTLD_GLOBAL, setup
* the pointer for the start of the search.
*/
if( pass == 1) {
rpnt1 = _dl_handles;
}
/*
* Anything after this, we need to skip to the next module.
*/
else if( pass >= 2) {
rpnt1 = rpnt1->next_handle;
}
/*
* Make sure we still have a module, and make sure that this
* module was loaded with RTLD_GLOBAL.
*/
if( pass != 0 )
{
if( rpnt1 == NULL ) break;
if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
}
for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables);
rpnt; rpnt = rpnt->next) {
tpnt = rpnt->dyn;
/*
* The idea here is that if we are using dlsym, we want to
* first search the entire chain loaded from dlopen, and
* return a result from that if we found anything. If this
* fails, then we continue the search into the stuff loaded
* when the image was activated. For normal lookups, we start
* with rpnt == NULL, so we should never hit this.
*/
if( tpnt->libtype == elf_executable
&& weak_result != 0 )
{
break;
}
/*
* Avoid calling .urem here.
*/
do_rem(hn, elf_hash_number, tpnt->nbucket);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] +
tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
/*
* This crap is required because the first instance of a
* symbol on the chain will be used for all symbol references.
* Thus this instance must be resolved to an address that
* contains the actual function,
*/
first_def = NULL;
for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
pnt = strtab + symtab[si].st_name;
if(_dl_strcmp(pnt, name) == 0 &&
(ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
symtab[si].st_value != 0) {
/* Here we make sure that we find a module where the symbol is
* actually defined.
*/
if(f_tpnt) {
if(!first_def) first_def = tpnt;
if(first_def == f_tpnt && symtab[si].st_shndx == 0)
continue;
}
switch(ELF32_ST_BIND(symtab[si].st_info)){
case STB_GLOBAL:
if ( tpnt->libtype != elf_executable
&& ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
break; /* nakao */
} else /* nakao */
return tpnt->loadaddr + symtab[si].st_value;
case STB_WEAK:
if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
break;
default: /* Do local symbols need to be examined? */
break;
}
}
}
}
}
if (data_result) return data_result; /* nakao */
return weak_result;
}

113
ldso/ldso/hash.h Normal file
View File

@@ -0,0 +1,113 @@
#include "link.h"
#ifndef RTLD_NEXT
#define RTLD_NEXT ((void*)-1)
#endif
struct dyn_elf{
unsigned int flags;
struct elf_resolve * dyn;
struct dyn_elf * next_handle; /* Used by dlopen et al. */
struct dyn_elf * next;
};
struct elf_resolve{
/* These entries must be in this order to be compatible with the interface used
by gdb to obtain the list of symbols. */
char * loadaddr;
char * libname;
unsigned int dynamic_addr;
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
struct dyn_elf * symbol_scope;
unsigned short usage_count;
unsigned short int init_flag;
unsigned int nbucket;
unsigned int * elf_buckets;
/*
* These are only used with ELF style shared libraries
*/
unsigned int nchain;
unsigned int * chains;
unsigned int dynamic_info[24];
unsigned int dynamic_size;
unsigned int n_phent;
struct elf_phdr * ppnt;
};
#if 0
/*
* The DT_DEBUG entry in the .dynamic section is given the address of this structure.
* gdb can pick this up to obtain the correct list of loaded modules.
*/
struct r_debug{
int r_version;
struct elf_resolve * link_map;
unsigned long brk_fun;
enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
unsigned long ldbase;
};
#endif
#define COPY_RELOCS_DONE 1
#define RELOCS_DONE 2
#define JMP_RELOCS_DONE 4
#define INIT_FUNCS_CALLED 8
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
extern struct dyn_elf * _dl_handles;
extern struct elf_resolve * _dl_check_hashed_files(char * libname);
extern struct elf_resolve * _dl_add_elf_hash_table(char * libname,
char * loadaddr,
unsigned int * dynamic_info,
unsigned int dynamic_addr,
unsigned int dynamic_size);
extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
unsigned int instr_addr,
struct elf_resolve * f_tpnt,
int copyrel);
extern int _dl_linux_dynamic_link(void);
#ifdef __mc68000__
/* On m68k constant strings are referenced through the GOT. */
/* XXX Requires load_addr to be defined. */
#define SEND_STDERR(X) \
{ const char *__s = (X); \
if (__s < (const char *) load_addr) __s += load_addr; \
_dl_write (2, __s, _dl_strlen (__s)); \
}
#else
#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
#endif
extern int _dl_fdprintf(int, const char *, ...);
extern char * _dl_library_path;
extern char * _dl_not_lazy;
extern char * _dl_strdup(const char *);
extern inline int _dl_symbol(char * name);
unsigned long _dl_elf_hash(const char * name);
extern inline int _dl_symbol(char * name)
{
if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
return 0;
return 1;
}
#define DL_ERROR_NOFILE 1
#define DL_ERROR_NOZERO 2
#define DL_ERROR_NOTELF 3
#define DL_ERROR_NOTMAGIC 4
#define DL_ERROR_NOTDYN 5
#define DL_ERROR_MMAP_FAILED 6
#define DL_ERROR_NODYNAMIC 7
#define DL_WRONG_RELOCS 8
#define DL_BAD_HANDLE 9
#define DL_NO_SYMBOL 10

View File

@@ -0,0 +1,82 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
/*
* Define this if the system uses RELOCA.
*/
#undef ELF_USES_RELOCA
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
/*
* Initialization sequence for a GOT.
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader. RELP is the relocation that we
* are performing, REL is the pointer to the address we are relocating.
* SYMBOL is the symbol involved in the relocation, and LOAD is the
* load address.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)){ \
case R_386_32: \
*REL += SYMBOL; \
break; \
case R_386_PC32: \
*REL += SYMBOL - (unsigned int) REL; \
break; \
case R_386_GLOB_DAT: \
case R_386_JMP_SLOT: \
*REL = SYMBOL; \
break; \
case R_386_RELATIVE: \
*REL += (unsigned int) LOAD; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done.
*/
#define START() \
__asm__ volatile ("leave\n\t" \
"jmp *%%eax\n\t" \
: "=a" (status) : \
"d" (_dl_interpreter_exit), "a" (_dl_elf_main))
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_386
#define MAGIC2 EM_486
/* Used for error messages */
#define ELF_TARGET "386/486"
extern unsigned int _dl_linux_resolver(int dummy, int i);
#define do_rem(result, n, base) result = (n % base)

321
ldso/ldso/i386/elfinterp.c Normal file
View File

@@ -0,0 +1,321 @@
/* Run an ELF binary on a linux system.
Copyright (C) 1993, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef VERBOSE_DLINKER
#define VERBOSE_DLINKER
#endif
#ifdef VERBOSE_DLINKER
static char * _dl_reltypes[] = {"R_386_NONE","R_386_32","R_386_PC32","R_386_GOT32",
"R_386_PLT32","R_386_COPY","R_386_GLOB_DAT",
"R_386_JMP_SLOT","R_386_RELATIVE","R_386_GOTOFF",
"R_386_GOTPC","R_386_NUM"};
#endif
/* Program to load an ELF binary on a linux system, and run it.
References to symbols in sharable libraries can be resolved by either
an ELF sharable library or a linux style of shared library. */
/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
I ever taken any courses on internals. This program was developed using
information available through the book "UNIX SYSTEM V RELEASE 4,
Programmers guide: Ansi C and Programming Support Tools", which did
a more than adequate job of explaining everything required to get this
working. */
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/elf.h>
#include "hash.h"
#include "linuxelf.h"
#include "../string.h"
#include "../syscall.h"
#define SVR4_COMPATIBILITY
extern char *_dl_progname;
extern int _dl_linux_resolve(void);
unsigned int _dl_linux_resolver(int dummy, int i)
{
unsigned int * sp;
int reloc_entry;
int reloc_type;
struct elf32_rel * this_reloc;
char * strtab;
struct elf32_sym * symtab;
struct elf32_rel * rel_addr;
struct elf_resolve * tpnt;
int symtab_index;
char * new_addr;
char ** got_addr;
unsigned int instr_addr;
sp = &i;
reloc_entry = sp[1];
tpnt = (struct elf_resolve *) sp[0];
rel_addr = (struct elf32_rel *) (tpnt->dynamic_info[DT_JMPREL] +
tpnt->loadaddr);
this_reloc = rel_addr + (reloc_entry >> 3);
reloc_type = ELF32_R_TYPE(this_reloc->r_info);
symtab_index = ELF32_R_SYM(this_reloc->r_info);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
if (reloc_type != R_386_JMP_SLOT) {
_dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n",
_dl_progname);
_dl_exit(1);
};
/* Address of jump instruction to fix up */
instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr);
got_addr = (char **) instr_addr;
#ifdef DEBUG
_dl_fdprintf(2, "Resolving symbol %s\n",
strtab + symtab[symtab_index].st_name);
#endif
/* Get the address of the GOT entry */
new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) got_addr, tpnt, 0);
if(!new_addr) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
_dl_exit(1);
};
/* #define DEBUG_LIBRARY */
#ifdef DEBUG_LIBRARY
if((unsigned int) got_addr < 0x40000000) {
_dl_fdprintf(2, "Calling library function: %s\n",
strtab + symtab[symtab_index].st_name);
} else {
*got_addr = new_addr;
}
#else
*got_addr = new_addr;
#endif
return (unsigned int) new_addr;
}
void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type){
int i;
char * strtab;
int reloc_type;
int symtab_index;
struct elf32_sym * symtab;
struct elf32_rel * rpnt;
unsigned int * reloc_addr;
/* Now parse the relocation information */
rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof(struct elf32_rel);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i++, rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
/* When the dynamic linker bootstrapped itself, it resolved some symbols.
Make sure we do not do them again */
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index && tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
switch(reloc_type){
case R_386_NONE: break;
case R_386_JMP_SLOT:
*reloc_addr += (unsigned int) tpnt->loadaddr;
break;
default:
_dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
#endif
if(symtab_index) _dl_fdprintf(2, "'%s'\n",
strtab + symtab[symtab_index].st_name);
_dl_exit(1);
};
};
}
int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type){
int i;
char * strtab;
int reloc_type;
int goof = 0;
struct elf32_sym * symtab;
struct elf32_rel * rpnt;
unsigned int * reloc_addr;
unsigned int symbol_addr;
int symtab_index;
/* Now parse the relocation information */
rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof(struct elf32_rel);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i++, rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index) {
if(tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) reloc_addr,
(reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0);
/*
* We want to allow undefined references to weak symbols - this might
* have been intentional. We should not be linking local symbols
* here, so all bases should be covered.
*/
if(!symbol_addr &&
ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
}
}
switch(reloc_type){
case R_386_NONE:
break;
case R_386_32:
*reloc_addr += symbol_addr;
break;
case R_386_PC32:
*reloc_addr += symbol_addr - (unsigned int) reloc_addr;
break;
case R_386_GLOB_DAT:
case R_386_JMP_SLOT:
*reloc_addr = symbol_addr;
break;
case R_386_RELATIVE:
*reloc_addr += (unsigned int) tpnt->loadaddr;
break;
case R_386_COPY:
#if 0 /* Do this later */
_dl_fdprintf(2, "Doing copy for symbol ");
if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
_dl_fdprintf(2, "\n");
_dl_memcpy((void *) symtab[symtab_index].st_value,
(void *) symbol_addr,
symtab[symtab_index].st_size);
#endif
break;
default:
_dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
#endif
if (symtab_index)
_dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
_dl_exit(1);
};
};
return goof;
}
/* This is done as a separate step, because there are cases where
information is first copied and later initialized. This results in
the wrong information being copied. Someone at Sun was complaining about
a bug in the handling of _COPY by SVr4, and this may in fact be what he
was talking about. Sigh. */
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
at all */
int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
int rel_size, int type)
{
int i;
char * strtab;
int reloc_type;
int goof = 0;
struct elf32_sym * symtab;
struct elf32_rel * rpnt;
unsigned int * reloc_addr;
unsigned int symbol_addr;
struct elf_resolve *tpnt;
int symtab_index;
/* Now parse the relocation information */
tpnt = xpnt->dyn;
rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof(struct elf32_rel);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i++, rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
if(reloc_type != R_386_COPY) continue;
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index) {
if(tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
xpnt->next, (int) reloc_addr, NULL, 1);
if(!symbol_addr) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
};
};
if (!goof)
_dl_memcpy((char *) symtab[symtab_index].st_value,
(char *) symbol_addr,
symtab[symtab_index].st_size);
};
return goof;
}

View File

@@ -0,0 +1,82 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
/*
* Define this if the system uses RELOCA.
*/
#undef ELF_USES_RELOCA
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
/*
* Initialization sequence for a GOT.
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader. RELP is the relocation that we
* are performing, REL is the pointer to the address we are relocating.
* SYMBOL is the symbol involved in the relocation, and LOAD is the
* load address.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)){ \
case R_386_32: \
*REL += SYMBOL; \
break; \
case R_386_PC32: \
*REL += SYMBOL - (unsigned int) REL; \
break; \
case R_386_GLOB_DAT: \
case R_386_JMP_SLOT: \
*REL = SYMBOL; \
break; \
case R_386_RELATIVE: \
*REL += (unsigned int) LOAD; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done.
*/
#define START() \
__asm__ volatile ("leave\n\t" \
"jmp *%%eax\n\t" \
: "=a" (status) : \
"d" (_dl_interpreter_exit), "a" (_dl_elf_main))
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_386
#define MAGIC2 EM_486
/* Used for error messages */
#define ELF_TARGET "386/486"
extern unsigned int _dl_linux_resolver(int dummy, int i);
#define do_rem(result, n, base) result = (n % base)

55
ldso/ldso/i386/resolve.S Normal file
View File

@@ -0,0 +1,55 @@
#if 0
#include <sysdep.h>
#endif
/*
* These are various helper routines that are needed to run an ELF image.
*/
#ifndef ALIGN
#define ALIGN 4
#endif
#ifndef NO_UNDERSCORE
#define RUN _linux_run
#define RESOLVE __dl_linux_resolve
#define EXIT __interpreter_exit
#define RESOLVER __dl_linux_resolver
#define INIT ___loader_bootstrap
#else
#define RUN linux_run
#define RESOLVE _dl_linux_resolve
#define RESOLVER _dl_linux_resolver
#define EXIT _interpreter_exit
#define INIT __loader_bootstrap
#endif
.text
.align ALIGN
.align 16
.globl RESOLVE
.type RESOLVE,@function
RESOLVE:
pusha /* preserve all regs */
lea 0x20(%esp),%eax /* eax = tpnt and reloc_entry params */
pushl 4(%eax) /* push copy of reloc_entry param */
pushl (%eax) /* push copy of tpnt param */
pushl %eax /* _dl_linux_resolver expects a dummy
* param - this could be removed */
#ifdef __PIC__
call .L24
.L24:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
movl RESOLVER@GOT(%ebx),%ebx /* eax = resolved func */
call *%ebx
#else
call RESOLVER
#endif
movl %eax,0x2C(%esp) /* store func addr over original
* tpnt param */
addl $0xC,%esp /* remove copy parameters */
popa /* restore regs */
ret $4 /* jump to func removing original
* reloc_entry param from stack */
.LFE2:
.size RESOLVE,.LFE2-RESOLVE

82
ldso/ldso/i386/sysdep.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
/*
* Define this if the system uses RELOCA.
*/
#undef ELF_USES_RELOCA
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here.
*/
#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
/*
* Initialization sequence for a GOT.
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader. RELP is the relocation that we
* are performing, REL is the pointer to the address we are relocating.
* SYMBOL is the symbol involved in the relocation, and LOAD is the
* load address.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)){ \
case R_386_32: \
*REL += SYMBOL; \
break; \
case R_386_PC32: \
*REL += SYMBOL - (unsigned int) REL; \
break; \
case R_386_GLOB_DAT: \
case R_386_JMP_SLOT: \
*REL = SYMBOL; \
break; \
case R_386_RELATIVE: \
*REL += (unsigned int) LOAD; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done.
*/
#define START() \
__asm__ volatile ("leave\n\t" \
"jmp *%%eax\n\t" \
: "=a" (status) : \
"d" (_dl_interpreter_exit), "a" (_dl_elf_main))
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_386
#define MAGIC2 EM_486
/* Used for error messages */
#define ELF_TARGET "386/486"
extern unsigned int _dl_linux_resolver(int dummy, int i);
#define do_rem(result, n, base) result = (n % base)

1005
ldso/ldso/ld-uClibc.c Normal file

File diff suppressed because it is too large Load Diff

113
ldso/ldso/ld_hash.h Normal file
View File

@@ -0,0 +1,113 @@
#include "link.h"
#ifndef RTLD_NEXT
#define RTLD_NEXT ((void*)-1)
#endif
struct dyn_elf{
unsigned int flags;
struct elf_resolve * dyn;
struct dyn_elf * next_handle; /* Used by dlopen et al. */
struct dyn_elf * next;
};
struct elf_resolve{
/* These entries must be in this order to be compatible with the interface used
by gdb to obtain the list of symbols. */
char * loadaddr;
char * libname;
unsigned int dynamic_addr;
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
struct dyn_elf * symbol_scope;
unsigned short usage_count;
unsigned short int init_flag;
unsigned int nbucket;
unsigned int * elf_buckets;
/*
* These are only used with ELF style shared libraries
*/
unsigned int nchain;
unsigned int * chains;
unsigned int dynamic_info[24];
unsigned int dynamic_size;
unsigned int n_phent;
struct elf_phdr * ppnt;
};
#if 0
/*
* The DT_DEBUG entry in the .dynamic section is given the address of this structure.
* gdb can pick this up to obtain the correct list of loaded modules.
*/
struct r_debug{
int r_version;
struct elf_resolve * link_map;
unsigned long brk_fun;
enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
unsigned long ldbase;
};
#endif
#define COPY_RELOCS_DONE 1
#define RELOCS_DONE 2
#define JMP_RELOCS_DONE 4
#define INIT_FUNCS_CALLED 8
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
extern struct dyn_elf * _dl_handles;
extern struct elf_resolve * _dl_check_hashed_files(char * libname);
extern struct elf_resolve * _dl_add_elf_hash_table(char * libname,
char * loadaddr,
unsigned int * dynamic_info,
unsigned int dynamic_addr,
unsigned int dynamic_size);
extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
unsigned int instr_addr,
struct elf_resolve * f_tpnt,
int copyrel);
extern int _dl_linux_dynamic_link(void);
#ifdef __mc68000__
/* On m68k constant strings are referenced through the GOT. */
/* XXX Requires load_addr to be defined. */
#define SEND_STDERR(X) \
{ const char *__s = (X); \
if (__s < (const char *) load_addr) __s += load_addr; \
_dl_write (2, __s, _dl_strlen (__s)); \
}
#else
#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
#endif
extern int _dl_fdprintf(int, const char *, ...);
extern char * _dl_library_path;
extern char * _dl_not_lazy;
extern char * _dl_strdup(const char *);
extern inline int _dl_symbol(char * name);
unsigned long _dl_elf_hash(const char * name);
extern inline int _dl_symbol(char * name)
{
if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
return 0;
return 1;
}
#define DL_ERROR_NOFILE 1
#define DL_ERROR_NOZERO 2
#define DL_ERROR_NOTELF 3
#define DL_ERROR_NOTMAGIC 4
#define DL_ERROR_NOTDYN 5
#define DL_ERROR_MMAP_FAILED 6
#define DL_ERROR_NODYNAMIC 7
#define DL_WRONG_RELOCS 8
#define DL_BAD_HANDLE 9
#define DL_NO_SYMBOL 10

112
ldso/ldso/ld_string.h Normal file
View File

@@ -0,0 +1,112 @@
#ifndef _LINUX_STRING_H_
#define _LINUX_STRING_H_
#include <linux/types.h> /* for size_t */
#ifndef NULL
#define NULL ((void *) 0)
#endif
extern inline char * _dl_strcpy(char * dst,const char *src)
{
register char *ptr = dst;
while (*src)
*dst++ = *src++;
*dst = '\0';
return ptr;
}
extern inline int _dl_strcmp(const char * s1,const char * s2)
{
unsigned register char c1, c2;
do {
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0')
return c1 - c2;
}
while (c1 == c2);
return c1 - c2;
}
extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
{
unsigned register char c1 = '\0';
unsigned register char c2 = '\0';
while (len > 0) {
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0' || c1 != c2)
return c1 - c2;
len--;
}
return c1 - c2;
}
extern inline char * _dl_strchr(const char * str,int c)
{
register char ch;
do {
if ((ch = *str) == c)
return (char *) str;
str++;
}
while (ch);
return 0;
}
extern inline size_t _dl_strlen(const char * str)
{
register char *ptr = (char *) str;
while (*ptr)
ptr++;
return (ptr - str);
}
extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
{
register char *a = dst;
register const char *b = src;
while (len--)
*a++ = *b++;
return dst;
}
extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
{
unsigned char *c1 = (unsigned char *)s1;
unsigned char *c2 = (unsigned char *)s2;
while (len--) {
if (*c1 != *c2)
return *c1 - *c2;
c1++;
c2++;
}
return 0;
}
extern inline void * _dl_memset(void * str,int c,size_t len)
{
register char *a = str;
while (len--)
*a++ = c;
return str;
}
#endif

108
ldso/ldso/ld_syscall.h Normal file
View File

@@ -0,0 +1,108 @@
#include <linux/types.h>
#include <asm/unistd.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
#endif
#define _dl_mmap_check_error(__res) \
(((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
/* Here are the definitions for some syscalls that are used
by the dynamic linker. The idea is that we want to be able
to call these before the errno symbol is dynamicly linked, so
we use our own version here. Note that we cannot assume any
dynamic linking at all, so we cannot return any error codes.
We just punt if there is an error. */
/* Do not include unistd.h, so gcc doesn't whine about
* _exit returning. It really doesn't return... */
#define __NR__dl_exit __NR_exit
static inline _syscall1(void, _dl_exit, int, status);
#define __NR__dl_close __NR_close
static inline _syscall1(int, _dl_close, int, fd);
#define __NR__dl_mmap_real __NR_mmap
static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long buffer[6];
buffer[0] = (unsigned long) addr;
buffer[1] = (unsigned long) size;
buffer[2] = (unsigned long) prot;
buffer[3] = (unsigned long) flags;
buffer[4] = (unsigned long) fd;
buffer[5] = (unsigned long) offset;
return (void *) _dl_mmap_real(buffer);
}
#define __NR__dl_open __NR_open
static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
#define __NR__dl_write __NR_write
static inline _syscall3(unsigned long, _dl_write, int, fd,
const void *, buf, unsigned long, count);
#define __NR__dl_read __NR_read
static inline _syscall3(unsigned long, _dl_read, int, fd,
const void *, buf, unsigned long, count);
#define __NR__dl_mprotect __NR_mprotect
static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
/* Pull in whatever this particular arch's kernel thinks the kernel version of
* struct stat should look like. It turns out that each arch has a different
* opinion on the subject, and different kernel revs use different names... */
#define __NR__dl_stat __NR_stat
#define stat kernel_stat
#define new_stat kernel_stat
#include <asm/stat.h>
#undef new_stat
#undef stat
static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
#define __NR__dl_munmap __NR_munmap
static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
#define __NR__dl_getuid __NR_getuid
static inline _syscall0(gid_t, _dl_getuid);
#define __NR__dl_geteuid __NR_geteuid
static inline _syscall0(uid_t, _dl_geteuid);
#define __NR__dl_getgid __NR_getgid
static inline _syscall0(gid_t, _dl_getgid);
#define __NR__dl_getegid __NR_getegid
static inline _syscall0(gid_t, _dl_getegid);
/*
* Not an actual syscall, but we need something in assembly to say whether
* this is OK or not.
*/
extern inline int _dl_suid_ok(void)
{
uid_t uid, euid, gid, egid;
uid = _dl_getuid();
euid = _dl_geteuid();
gid = _dl_getgid();
egid = _dl_getegid();
if(uid == euid && gid == egid)
return 1;
else
return 0;
}

1005
ldso/ldso/ldso.c Normal file

File diff suppressed because it is too large Load Diff

37
ldso/ldso/link.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef _LINK_H
#define _LINK_H
#include "elf.h"
/* Header file that describes the internal data structures used by the
* ELF dynamic linker. */
struct link_map
{
/* These entries must be in this order to be compatible with the
* interface used by gdb to obtain the list of symbols. */
unsigned long l_addr; /* address at which object is mapped */
char *l_name; /* full name of loaded object */
Elf32_Dyn *l_ld; /* dynamic structure of object */
struct link_map *l_next;
struct link_map *l_prev;
};
/* The DT_DEBUG entry in the .dynamic section is given the address of
* this structure. gdb can pick this up to obtain the correct list of
* loaded modules. */
struct r_debug
{
int r_version; /* debugging info version no */
struct link_map *r_map; /* address of link_map */
unsigned long r_brk; /* address of update routine */
enum
{
RT_CONSISTENT,
RT_ADD,
RT_DELETE
} r_state;
unsigned long r_ldbase; /* base addr of ld.so */
};
#endif /* _LINK_H */

137
ldso/ldso/linuxelf.h Normal file
View File

@@ -0,0 +1,137 @@
/* This should eventually appear in the distribution version of linux/elf.h */
#ifndef R_SPARC_NONE
#define R_SPARC_NONE 0
#define R_SPARC_8 1
#define R_SPARC_16 2
#define R_SPARC_32 3
#define R_SPARC_DISP8 4
#define R_SPARC_DISP16 5
#define R_SPARC_DISP32 6
#define R_SPARC_WDISP30 7
#define R_SPARC_WDISP22 8
#define R_SPARC_HI22 9
#define R_SPARC_22 10
#define R_SPARC_13 11
#define R_SPARC_LO10 12
#define R_SPARC_GOT10 13
#define R_SPARC_GOT13 14
#define R_SPARC_GOT22 15
#define R_SPARC_PC10 16
#define R_SPARC_PC22 17
#define R_SPARC_WPLT30 18
#define R_SPARC_COPY 19
#define R_SPARC_GLOB_DAT 20
#define R_SPARC_JMP_SLOT 21
#define R_SPARC_RELATIVE 22
#define R_SPARC_UA32 23
#endif
#ifndef R_68K_NONE
#define R_68K_NONE 0
#define R_68K_32 1
#define R_68K_16 2
#define R_68K_8 3
#define R_68K_PC32 4
#define R_68K_PC16 5
#define R_68K_PC8 6
#define R_68K_GOT32 7
#define R_68K_GOT16 8
#define R_68K_GOT8 9
#define R_68K_GOT32O 10
#define R_68K_GOT16O 11
#define R_68K_GOT8O 12
#define R_68K_PLT32 13
#define R_68K_PLT16 14
#define R_68K_PLT8 15
#define R_68K_PLT32O 16
#define R_68K_PLT16O 17
#define R_68K_PLT8O 18
#define R_68K_COPY 19
#define R_68K_GLOB_DAT 20
#define R_68K_JMP_SLOT 21
#define R_68K_RELATIVE 22
#define R_68K_NUM 23
#endif
/*
* These constants define the elements of the auxiliary vector used to
* pass additional information from the kernel to an ELF application.
*/
#ifndef AT_NULL
typedef struct
{
int a_type;
union{
long a_val;
void *p_ptr;
void (*a_fcn)();
} a_un;
} auxv_t;
/*
* Values of a_type... These often appear in the file /usr/include/sys/auxv.h
* on SVr4 systems.
*/
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#endif
#ifndef AT_NOTELF
#define AT_NOTELF 10 /* program is not ELF */
#define AT_UID 11 /* real uid */
#define AT_EUID 12 /* effective uid */
#define AT_GID 13 /* real gid */
#define AT_EGID 14 /* effective gid */
#endif
extern int _dl_linux_resolve(void);
extern struct elf_resolve * _dl_load_shared_library(int secure,
struct elf_resolve *, char * libname);
extern void * _dl_malloc(int size);
extern int _dl_map_cache(void);
extern int _dl_unmap_cache(void);
extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
char * libname, int);
int _dl_copy_fixups(struct dyn_elf * tpnt);
extern int linux_run(int argc, char * argv[]);
extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type);
extern int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type);
extern int _dl_parse_copy_information(struct dyn_elf * rpnt, int rel_addr,
int rel_size, int type);
/* This means that we may be forced to manually search for copy fixups
which were omitted by the linker. We cannot depend upon the DT_TEXTREL
to tell us whether there are fixups in a text section or not. */
#ifndef SVR4_BUGCOMPAT
#define SVR4_BUGCOMPAT 1
#endif
#ifndef PF_R
#define PF_R 4
#define PF_W 2
#define PF_X 1
#endif
/* Convert between the Linux flags for page protections and the
ones specified in the ELF standard. */
#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
(((X) & PF_W) ? PROT_WRITE : 0) | \
(((X) & PF_X) ? PROT_EXEC : 0))

View File

@@ -0,0 +1,87 @@
/* Various assmbly language/system dependent hacks that are required
so that we can minimize the amount of platform specific code. */
/* Define this if the system uses RELOCA. */
#define ELF_USES_RELOCA
/* Get a pointer to the argv array. On many platforms this can be
just the address if the first argument, on other platforms we need
to do something a little more subtle here. */
#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
/* Get the address of the Global offset table. This must be absolute,
not relative. */
#define GET_GOT(X) __asm__ ("movel %%a5,%0" : "=g" (X))
/* Initialization sequence for a GOT. */
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) (MODULE); \
}
/* Here is a macro to perform a relocation. This is only used when
bootstrapping the dynamic loader. RELP is the relocation that we
are performing, REL is the pointer to the address we are
relocating. SYMBOL is the symbol involved in the relocation, and
LOAD is the load address. */
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch (ELF32_R_TYPE ((RELP)->r_info)) \
{ \
case R_68K_8: \
*(char *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_16: \
*(short *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_32: \
*(REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_PC8: \
*(char *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC16: \
*(short *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC32: \
*(REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_GLOB_DAT: \
case R_68K_JMP_SLOT: \
*(REL) = (SYMBOL); \
break; \
case R_68K_RELATIVE: /* Compatibility kludge */ \
*(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
break; \
default: \
_dl_exit (1); \
}
/* Transfer control to the user's application, once the dynamic loader
is done. */
#define START() \
__asm__ volatile ("unlk %%a6\n\t" \
"jmp %0@" \
: : "a" (_dl_elf_main));
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_68K
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "m68k"
struct elf_resolve;
extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
/* Define this because we do not want to call .udiv in the library.
Not needed for m68k. */
#define do_rem(result, n, base) ((result) = (n) % (base))

358
ldso/ldso/m68k/elfinterp.c Normal file
View File

@@ -0,0 +1,358 @@
/* Run an ELF binary on a linux system.
Copyright (C) 1993, Eric Youngdale.
Copyright (C) 1995, Andreas Schwab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Adapted to ELF/68k by Andreas Schwab. */
#ifndef VERBOSE_DLINKER
#define VERBOSE_DLINKER
#endif
#ifdef VERBOSE_DLINKER
static char *_dl_reltypes[] =
{
"R_68K_NONE",
"R_68K_32", "R_68K_16", "R_68K_8",
"R_68K_PC32", "R_68K_PC16", "R_68K_PC8",
"R_68K_GOT32", "R_68K_GOT16", "R_68K_GOT8",
"R_68K_GOT32O", "R_68K_GOT16O", "R_68K_GOT8O",
"R_68K_PLT32", "R_68K_PLT16", "R_68K_PLT8",
"R_68K_PLT32O", "R_68K_PLT16O", "R_68K_PLT8O",
"R_68K_COPY", "R_68K_GLOB_DAT", "R_68K_JMP_SLOT", "R_68K_RELATIVE",
"R_68K_NUM"
};
#endif
/* Program to load an ELF binary on a linux system, and run it.
References to symbols in sharable libraries can be resolved by either
an ELF sharable library or a linux style of shared library. */
/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
I ever taken any courses on internals. This program was developed using
information available through the book "UNIX SYSTEM V RELEASE 4,
Programmers guide: Ansi C and Programming Support Tools", which did
a more than adequate job of explaining everything required to get this
working. */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/unistd.h>
/*#include <stdlib.h>*/
#include "string.h"
#include <linux/unistd.h>
#include <linux/fcntl.h>
#include <linux/elf.h>
#include "hash.h"
#include "linuxelf.h"
#include "sysdep.h"
#include "../syscall.h"
#include "../string.h"
extern char *_dl_progname;
unsigned int
_dl_linux_resolver (int dummy1, int dummy2,
struct elf_resolve *tpnt, int reloc_entry)
{
int reloc_type;
struct elf32_rela *this_reloc;
char *strtab;
struct elf32_sym *symtab;
char *rel_addr;
int symtab_index;
char *new_addr;
char **got_addr;
unsigned int instr_addr;
rel_addr = tpnt->loadaddr + tpnt->dynamic_info[DT_JMPREL];
this_reloc = (struct elf32_rela *) (rel_addr + reloc_entry);
reloc_type = ELF32_R_TYPE (this_reloc->r_info);
symtab_index = ELF32_R_SYM (this_reloc->r_info);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
if (reloc_type != R_68K_JMP_SLOT)
{
_dl_fdprintf (2, "%s: incorrect relocation type in jump relocations\n",
_dl_progname);
_dl_exit (1);
}
/* Address of jump instruction to fix up. */
instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr;
got_addr = (char **) instr_addr;
#ifdef DEBUG
_dl_fdprintf (2, "Resolving symbol %s\n",
strtab + symtab[symtab_index].st_name);
#endif
/* Get the address of the GOT entry. */
new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) got_addr, tpnt, 0);
if (!new_addr)
{
_dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
_dl_exit (1);
}
/* #define DEBUG_LIBRARY */
#ifdef DEBUG_LIBRARY
if ((unsigned int) got_addr < 0x40000000)
_dl_fdprintf (2, "Calling library function: %s\n",
strtab + symtab[symtab_index].st_name);
else
#endif
*got_addr = new_addr;
return (unsigned int) new_addr;
}
void
_dl_parse_lazy_relocation_information (struct elf_resolve *tpnt, int rel_addr,
int rel_size, int type)
{
int i;
char *strtab;
int reloc_type;
int symtab_index;
struct elf32_sym *symtab;
struct elf32_rela *rpnt;
unsigned int *reloc_addr;
/* Now parse the relocation information. */
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof (struct elf32_rela);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for (i = 0; i < rel_size; i++, rpnt++)
{
reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
reloc_type = ELF32_R_TYPE (rpnt->r_info);
symtab_index = ELF32_R_SYM (rpnt->r_info);
/* When the dynamic linker bootstrapped itself, it resolved some symbols.
Make sure we do not do them again. */
if (tpnt->libtype == program_interpreter
&& (!symtab_index
|| _dl_symbol (strtab + symtab[symtab_index].st_name)))
continue;
switch (reloc_type)
{
case R_68K_NONE:
break;
case R_68K_JMP_SLOT:
*reloc_addr += (unsigned int) tpnt->loadaddr;
break;
default:
_dl_fdprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
#endif
if (symtab_index)
_dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
_dl_fdprintf (2, "\n");
_dl_exit (1);
}
}
}
int
_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr,
int rel_size, int type)
{
int i;
char *strtab;
int reloc_type;
int goof = 0;
struct elf32_sym *symtab;
struct elf32_rela *rpnt;
unsigned int *reloc_addr;
unsigned int symbol_addr;
int symtab_index;
/* Now parse the relocation information */
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof (struct elf32_rela);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for (i = 0; i < rel_size; i++, rpnt++)
{
reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
reloc_type = ELF32_R_TYPE (rpnt->r_info);
symtab_index = ELF32_R_SYM (rpnt->r_info);
symbol_addr = 0;
if (tpnt->libtype == program_interpreter
&& (!symtab_index
|| _dl_symbol (strtab + symtab[symtab_index].st_name)))
continue;
if (symtab_index)
{
symbol_addr = (unsigned int)
_dl_find_hash (strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) reloc_addr,
reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, 0);
/* We want to allow undefined references to weak symbols -
this might have been intentional. We should not be
linking local symbols here, so all bases should be
covered. */
if (!symbol_addr
&& ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_GLOBAL)
{
_dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
}
}
switch (reloc_type)
{
case R_68K_NONE:
break;
case R_68K_8:
*(char *) reloc_addr = symbol_addr + rpnt->r_addend;
break;
case R_68K_16:
*(short *) reloc_addr = symbol_addr + rpnt->r_addend;
break;
case R_68K_32:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
case R_68K_PC8:
*(char *) reloc_addr = (symbol_addr + rpnt->r_addend
- (unsigned int) reloc_addr);
break;
case R_68K_PC16:
*(short *) reloc_addr = (symbol_addr + rpnt->r_addend
- (unsigned int) reloc_addr);
break;
case R_68K_PC32:
*reloc_addr = (symbol_addr + rpnt->r_addend
- (unsigned int) reloc_addr);
break;
case R_68K_GLOB_DAT:
case R_68K_JMP_SLOT:
*reloc_addr = symbol_addr;
break;
case R_68K_RELATIVE:
*reloc_addr = ((unsigned int) tpnt->loadaddr
/* Compatibility kludge. */
+ (rpnt->r_addend ? : *reloc_addr));
break;
case R_68K_COPY:
#if 0 /* Do this later. */
_dl_fdprintf (2, "Doing copy");
if (symtab_index)
_dl_fdprintf (2, " for symbol %s",
strtab + symtab[symtab_index].st_name);
_dl_fdprintf (2, "\n");
_dl_memcpy ((void *) symtab[symtab_index].st_value,
(void *) symbol_addr,
symtab[symtab_index].st_size);
#endif
break;
default:
_dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
#endif
if (symtab_index)
_dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
_dl_fdprintf (2, "\n");
_dl_exit (1);
}
}
return goof;
}
/* This is done as a separate step, because there are cases where
information is first copied and later initialized. This results in
the wrong information being copied. Someone at Sun was complaining about
a bug in the handling of _COPY by SVr4, and this may in fact be what he
was talking about. Sigh. */
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
at all. */
int
_dl_parse_copy_information (struct dyn_elf *xpnt, int rel_addr,
int rel_size, int type)
{
int i;
char *strtab;
int reloc_type;
int goof = 0;
struct elf32_sym *symtab;
struct elf32_rela *rpnt;
unsigned int *reloc_addr;
unsigned int symbol_addr;
struct elf_resolve *tpnt;
int symtab_index;
/* Now parse the relocation information */
tpnt = xpnt->dyn;
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
rel_size = rel_size / sizeof (struct elf32_rela);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for (i = 0; i < rel_size; i++, rpnt++)
{
reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
reloc_type = ELF32_R_TYPE (rpnt->r_info);
if (reloc_type != R_68K_COPY)
continue;
symtab_index = ELF32_R_SYM (rpnt->r_info);
symbol_addr = 0;
if (tpnt->libtype == program_interpreter
&& (!symtab_index
|| _dl_symbol (strtab + symtab[symtab_index].st_name)))
continue;
if (symtab_index)
{
symbol_addr = (unsigned int)
_dl_find_hash (strtab + symtab[symtab_index].st_name,
xpnt->next, (int) reloc_addr, NULL, 1);
if (!symbol_addr)
{
_dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
}
}
if (!goof)
_dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
symtab[symtab_index].st_size);
}
return goof;
}

View File

@@ -0,0 +1,87 @@
/* Various assmbly language/system dependent hacks that are required
so that we can minimize the amount of platform specific code. */
/* Define this if the system uses RELOCA. */
#define ELF_USES_RELOCA
/* Get a pointer to the argv array. On many platforms this can be
just the address if the first argument, on other platforms we need
to do something a little more subtle here. */
#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
/* Get the address of the Global offset table. This must be absolute,
not relative. */
#define GET_GOT(X) __asm__ ("movel %%a5,%0" : "=g" (X))
/* Initialization sequence for a GOT. */
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) (MODULE); \
}
/* Here is a macro to perform a relocation. This is only used when
bootstrapping the dynamic loader. RELP is the relocation that we
are performing, REL is the pointer to the address we are
relocating. SYMBOL is the symbol involved in the relocation, and
LOAD is the load address. */
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch (ELF32_R_TYPE ((RELP)->r_info)) \
{ \
case R_68K_8: \
*(char *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_16: \
*(short *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_32: \
*(REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_PC8: \
*(char *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC16: \
*(short *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC32: \
*(REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_GLOB_DAT: \
case R_68K_JMP_SLOT: \
*(REL) = (SYMBOL); \
break; \
case R_68K_RELATIVE: /* Compatibility kludge */ \
*(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
break; \
default: \
_dl_exit (1); \
}
/* Transfer control to the user's application, once the dynamic loader
is done. */
#define START() \
__asm__ volatile ("unlk %%a6\n\t" \
"jmp %0@" \
: : "a" (_dl_elf_main));
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_68K
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "m68k"
struct elf_resolve;
extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
/* Define this because we do not want to call .udiv in the library.
Not needed for m68k. */
#define do_rem(result, n, base) ((result) = (n) % (base))

29
ldso/ldso/m68k/resolve.S Normal file
View File

@@ -0,0 +1,29 @@
#if 0
#include <sysdep.h>
#endif
/*
* These are various helper routines that are needed to run an ELF image.
*/
#ifdef NO_UNDERSCORE
#define __dl_linux_resolve _dl_linux_resolve
#define __dl_linux_resolver _dl_linux_resolver
#endif
.text
.even
.globl __dl_linux_resolve
.type __dl_linux_resolve,@function
__dl_linux_resolve:
moveml %a0/%a1,%sp@-
#ifdef __PIC__
bsrl __dl_linux_resolver@PLTPC
#else
jbsr __dl_linux_resolver
#endif
moveml %sp@+,%a0/%a1
addql #8,%sp
jmp @(%d0)
.LFE2:
.size __dl_linux_resolve,.LFE2-__dl_linux_resolve

87
ldso/ldso/m68k/sysdep.h Normal file
View File

@@ -0,0 +1,87 @@
/* Various assmbly language/system dependent hacks that are required
so that we can minimize the amount of platform specific code. */
/* Define this if the system uses RELOCA. */
#define ELF_USES_RELOCA
/* Get a pointer to the argv array. On many platforms this can be
just the address if the first argument, on other platforms we need
to do something a little more subtle here. */
#define GET_ARGV(ARGVP, ARGS) ((ARGVP) = ((unsigned int *) &(ARGS)))
/* Get the address of the Global offset table. This must be absolute,
not relative. */
#define GET_GOT(X) __asm__ ("movel %%a5,%0" : "=g" (X))
/* Initialization sequence for a GOT. */
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[2] = (int) _dl_linux_resolve; \
GOT_BASE[1] = (int) (MODULE); \
}
/* Here is a macro to perform a relocation. This is only used when
bootstrapping the dynamic loader. RELP is the relocation that we
are performing, REL is the pointer to the address we are
relocating. SYMBOL is the symbol involved in the relocation, and
LOAD is the load address. */
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch (ELF32_R_TYPE ((RELP)->r_info)) \
{ \
case R_68K_8: \
*(char *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_16: \
*(short *) (REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_32: \
*(REL) = (SYMBOL) + (RELP)->r_addend; \
break; \
case R_68K_PC8: \
*(char *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC16: \
*(short *) (REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_PC32: \
*(REL) = ((SYMBOL) + (RELP)->r_addend \
- (unsigned int) (REL)); \
break; \
case R_68K_GLOB_DAT: \
case R_68K_JMP_SLOT: \
*(REL) = (SYMBOL); \
break; \
case R_68K_RELATIVE: /* Compatibility kludge */ \
*(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
break; \
default: \
_dl_exit (1); \
}
/* Transfer control to the user's application, once the dynamic loader
is done. */
#define START() \
__asm__ volatile ("unlk %%a6\n\t" \
"jmp %0@" \
: : "a" (_dl_elf_main));
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_68K
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "m68k"
struct elf_resolve;
extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
/* Define this because we do not want to call .udiv in the library.
Not needed for m68k. */
#define do_rem(result, n, base) ((result) = (n) % (base))

588
ldso/ldso/readelflib1.c Normal file
View File

@@ -0,0 +1,588 @@
/* Load an ELF sharable library into memory.
Copyright (C) 1993-1996, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file contains the helper routines to load an ELF sharable
library into memory and add the symbol table info to the chain. */
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include "string.h"
/*#include <stdlib.h>*/
#include <linux/mman.h>
#include <linux/stat.h>
#include "hash.h"
#include "linuxelf.h"
#include "sysdep.h"
#include <linux/unistd.h>
#include "syscall.h"
#ifdef USE_CACHE
#include "../config.h"
#endif
extern char *_dl_progname;
#ifdef USE_CACHE
static caddr_t _dl_cache_addr = NULL;
static size_t _dl_cache_size = 0;
int _dl_map_cache(void)
{
int fd;
struct kernel_stat st;
header_t *header;
libentry_t *libent;
int i, strtabsize;
if (_dl_cache_addr == (caddr_t)-1)
return -1;
else if (_dl_cache_addr != NULL)
return 0;
if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
{
_dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
_dl_cache_addr = (caddr_t)-1; /* so we won't try again */
return -1;
}
_dl_cache_size = st.st_size;
_dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
MAP_SHARED, fd, 0);
_dl_close (fd);
if (_dl_cache_addr == (caddr_t)-1)
{
_dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
return -1;
}
header = (header_t *)_dl_cache_addr;
if (_dl_cache_size < sizeof (header_t) ||
_dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
_dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
_dl_cache_size <
(sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
_dl_cache_addr[_dl_cache_size-1] != '\0')
{
_dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
goto fail;
}
strtabsize = _dl_cache_size - sizeof (header_t) -
header->nlibs * sizeof (libentry_t);
libent = (libentry_t *)&header[1];
for (i = 0; i < header->nlibs; i++)
{
if (libent[i].sooffset >= strtabsize ||
libent[i].liboffset >= strtabsize)
{
_dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
goto fail;
}
}
return 0;
fail:
_dl_munmap(_dl_cache_addr, _dl_cache_size);
_dl_cache_addr = (caddr_t)-1;
return -1;
}
int _dl_unmap_cache(void)
{
if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
return -1;
#if 1
_dl_munmap (_dl_cache_addr, _dl_cache_size);
_dl_cache_addr = NULL;
#endif
return 0;
}
#endif
/*
* Used to return error codes back to dlopen et. al.
*/
unsigned int _dl_error_number;
unsigned int _dl_internal_error_number;
struct elf_resolve * _dl_load_shared_library(int secure,
struct elf_resolve * tpnt, char * full_libname) {
char * pnt, *pnt1, *pnt2;
struct elf_resolve *tpnt1 = NULL;
char mylibname[2050];
char * libname;
_dl_internal_error_number = 0;
/* quick hack to ensure mylibname buffer doesn't overflow. don't
allow full_libname or any directory to be longer than 1024. */
if (_dl_strlen(full_libname) > 1024)
goto goof;
pnt = libname = full_libname;
while (*pnt) {
if(*pnt == '/') libname = pnt+1;
pnt++;
}
/* If the filename has any '/', try it straight and leave it at that.
For IBCS2 compatibility under linux, we substitute the string
/usr/i486-sysv4/lib for /usr/lib in library names. */
if (libname != full_libname) {
tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
if (tpnt1)
return tpnt1;
goto goof;
}
/*
* The ABI specifies that RPATH is searched before LD_*_PATH or
* the default path of /usr/lib.
* Check in rpath directories
*/
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
if (tpnt->libtype == elf_executable) {
pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
if(pnt1) {
pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
while(*pnt1){
pnt2 = mylibname;
while(*pnt1 && *pnt1 != ':') {
if (pnt2 - mylibname < 1024)
*pnt2++ = *pnt1++;
else
pnt1++;
}
if (pnt2 - mylibname >= 1024)
break;
if(pnt2[-1] != '/') *pnt2++ = '/';
pnt = libname;
while(*pnt) *pnt2++ = *pnt++;
*pnt2++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if(tpnt1) return tpnt1;
if(*pnt1 == ':') pnt1++;
}
}
}
}
/* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
pnt1 = _dl_library_path;
if (pnt1 && *pnt1) {
while (*pnt1) {
pnt2 = mylibname;
while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
if (pnt2 - mylibname < 1024)
*pnt2++ = *pnt1++;
else
pnt1++;
}
if (pnt2 - mylibname >= 1024)
break;
if(pnt2[-1] != '/') *pnt2++ = '/';
pnt = libname;
while(*pnt) *pnt2++ = *pnt++;
*pnt2++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if(tpnt1) return tpnt1;
if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
}
}
/*
* Where should the cache be searched? There is no such concept in the
* ABI, so we have some flexibility here. For now, search it before
* the default path of /usr/lib.
*/
#ifdef USE_CACHE
if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
{
int i;
header_t *header = (header_t *)_dl_cache_addr;
libentry_t *libent = (libentry_t *)&header[1];
char *strs = (char *)&libent[header->nlibs];
for (i = 0; i < header->nlibs; i++)
{
if ((libent[i].flags == LIB_ELF ||
libent[i].flags == LIB_ELF_LIBC5) &&
_dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
(tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
return tpnt1;
}
}
#endif
#ifdef UCLIBC_DEVEL
/* Check in /usr/<arch>-linux-uclibc/lib */
pnt1 = UCLIBC_INSTALL_DIR"/lib";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
#else /* UCLIBC_DEVEL */
/* Check in /usr/lib */
pnt1 = "/usr/lib/";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
/* Check in /lib */
/* try "/lib/". */
pnt1 = "/lib/";
pnt = mylibname;
while(*pnt1) *pnt++ = *pnt1++;
pnt1 = libname;
while(*pnt1) *pnt++ = *pnt1++;
*pnt++ = 0;
tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
if (tpnt1) return tpnt1;
#endif /* UCLIBC_DEVEL */
goof:
/* Well, we shot our wad on that one. All we can do now is punt */
if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
else _dl_error_number = DL_ERROR_NOFILE;
return NULL;
}
/*
* Read one ELF library into memory, mmap it into the correct locations and
* add the symbol info to the symbol chain. Perform any relocations that
* are required.
*/
//extern _elf_rtbndr(void);
struct elf_resolve * _dl_load_elf_shared_library(int secure,
char * libname, int flag) {
struct elfhdr * epnt;
unsigned int dynamic_addr = 0;
unsigned int dynamic_size = 0;
struct dynamic * dpnt;
struct elf_resolve * tpnt;
struct elf_phdr * ppnt;
int piclib;
char * status;
int flags;
char header[4096];
int dynamic_info[24];
int * lpnt;
unsigned int libaddr;
unsigned int minvma=0xffffffff, maxvma=0;
int i;
int infile;
/* If this file is already loaded, skip this step */
tpnt = _dl_check_hashed_files(libname);
if(tpnt) return tpnt;
/* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
we don't load the library if it isn't setuid. */
if (secure) {
struct kernel_stat st;
if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
return NULL;
}
libaddr = 0;
infile = _dl_open(libname, O_RDONLY);
if(infile < 0)
{
#if 0
/*
* NO! When we open shared libraries we may search several paths.
* it is inappropriate to generate an error here.
*/
_dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
#endif
_dl_internal_error_number = DL_ERROR_NOFILE;
return NULL;
}
_dl_read(infile, header, sizeof(header));
epnt = (struct elfhdr *) header;
if (epnt->e_ident[0] != 0x7f ||
epnt->e_ident[1] != 'E' ||
epnt->e_ident[2] != 'L' ||
epnt->e_ident[3] != 'F') {
_dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_NOTELF;
_dl_close(infile);
return NULL;
};
if((epnt->e_type != ET_DYN) ||
(epnt->e_machine != MAGIC1
#ifdef MAGIC2
&& epnt->e_machine != MAGIC2
#endif
)){
_dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
_dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
_dl_progname, libname);
_dl_close(infile);
return NULL;
};
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
piclib = 1;
for(i=0;i < epnt->e_phnum; i++){
if(ppnt->p_type == PT_DYNAMIC) {
if (dynamic_addr)
_dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
_dl_progname, libname);
dynamic_addr = ppnt->p_vaddr;
dynamic_size = ppnt->p_filesz;
};
if(ppnt->p_type == PT_LOAD) {
/* See if this is a PIC library. */
if(i == 0 && ppnt->p_vaddr > 0x1000000) {
piclib = 0;
minvma=ppnt->p_vaddr;
}
if(piclib && ppnt->p_vaddr < minvma) {
minvma = ppnt->p_vaddr;
}
if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
maxvma = ppnt->p_vaddr + ppnt->p_memsz;
}
}
ppnt++;
};
maxvma=(maxvma+0xfffU)&~0xfffU;
minvma=minvma&~0xffffU;
flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
if(!piclib) flags |= MAP_FIXED;
status = (char *) _dl_mmap((char *) (piclib?0:minvma),
maxvma-minvma,
PROT_NONE,
flags | MAP_ANONYMOUS, -1,
0);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_close(infile);
return NULL;
};
libaddr=(unsigned int)status;
flags|=MAP_FIXED;
/* Get the memory to store the library */
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
for(i=0;i < epnt->e_phnum; i++){
if(ppnt->p_type == PT_LOAD) {
/* See if this is a PIC library. */
if(i == 0 && ppnt->p_vaddr > 0x1000000) {
piclib = 0;
/* flags |= MAP_FIXED; */
}
if(ppnt->p_flags & PF_W) {
unsigned int map_size;
char * cpnt;
status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) +
(ppnt->p_vaddr & 0xfffff000)),
(ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
LXFLAGS(ppnt->p_flags),
flags, infile,
ppnt->p_offset & 0x7ffff000);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_munmap((char *)libaddr, maxvma-minvma);
_dl_close(infile);
return NULL;
};
/* Pad the last page with zeroes. */
cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
/* I am not quite sure if this is completely correct to do or not, but
the basic way that we handle bss segments is that we mmap /dev/zero if
there are any pages left over that are not mapped as part of the file */
map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0),
ppnt->p_vaddr + ppnt->p_memsz - map_size,
LXFLAGS(ppnt->p_flags),
flags | MAP_ANONYMOUS, -1, 0);
} else
status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) +
(piclib?libaddr:0),
(ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
LXFLAGS(ppnt->p_flags),
flags, infile,
ppnt->p_offset & 0x7ffff000);
if(_dl_mmap_check_error(status)) {
_dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
_dl_internal_error_number = DL_ERROR_MMAP_FAILED;
_dl_munmap((char *)libaddr, maxvma-minvma);
_dl_close(infile);
return NULL;
};
/* if(libaddr == 0 && piclib) {
libaddr = (unsigned int) status;
flags |= MAP_FIXED;
}; */
};
ppnt++;
};
_dl_close(infile);
/* For a non-PIC library, the addresses are all absolute */
if(piclib) {
dynamic_addr += (unsigned int) libaddr;
}
/*
* OK, the ELF library is now loaded into VM in the correct locations
* The next step is to go through and do the dynamic linking (if needed).
*/
/* Start by scanning the dynamic section to get all of the pointers */
if(!dynamic_addr) {
_dl_internal_error_number = DL_ERROR_NODYNAMIC;
_dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
return NULL;
}
dpnt = (struct dynamic *) dynamic_addr;
dynamic_size = dynamic_size / sizeof(struct dynamic);
_dl_memset(dynamic_info, 0, sizeof(dynamic_info));
for(i=0; i< dynamic_size; i++){
if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
if(dpnt->d_tag == DT_TEXTREL ||
SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
dpnt++;
};
/* If the TEXTREL is set, this means that we need to make the pages
writable before we perform relocations. Do this now. They get set back
again later. */
if (dynamic_info[DT_TEXTREL]) {
ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
for(i=0;i < epnt->e_phnum; i++, ppnt++){
if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
_dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
(ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
PROT_READ | PROT_WRITE | PROT_EXEC);
}
}
tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr,
dynamic_size);
tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
tpnt->n_phent = epnt->e_phnum;
/*
* OK, the next thing we need to do is to insert the dynamic linker into
* the proper entry in the GOT so that the PLT symbols can be properly
* resolved.
*/
lpnt = (int *) dynamic_info[DT_PLTGOT];
if(lpnt) {
lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
INIT_GOT(lpnt, tpnt);
};
return tpnt;
}
/* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY
relocations for global variables that are present both in the image and
the shared library. Go through and do it manually. If the images
are guaranteed to be generated by a trustworthy linker, then this
step can be skipped. */
int _dl_copy_fixups(struct dyn_elf * rpnt)
{
int goof = 0;
struct elf_resolve * tpnt;
if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
else return 0;
tpnt = rpnt->dyn;
if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
tpnt->init_flag |= COPY_RELOCS_DONE;
#ifdef ELF_USES_RELOCA
goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
tpnt->dynamic_info[DT_RELASZ], 0);
#else
goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
tpnt->dynamic_info[DT_RELSZ], 0);
#endif
return goof;
}

5
ldso/ldso/sparc/DEFS.h Normal file
View File

@@ -0,0 +1,5 @@
#define FUNC(name) \
.global name; \
.type name,@function; \
.align 4; \
name:

131
ldso/ldso/sparc/dl-sysdep.h Normal file
View File

@@ -0,0 +1,131 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
#define LINUXBIN
/*
* Define this if the system uses RELOCA.
*/
#define ELF_USES_RELOCA
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here. We assume that argc is stored
* at the word just below the argvp that we return here.
*/
#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
/*
* Initialization sequence for a GOT. For the Sparc, this points to the
* PLT, and we need to initialize a couple of the slots. The PLT should
* look like:
*
* save %sp, -64, %sp
* call _dl_linux_resolve
* nop
* .word implementation_dependent
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
GOT_BASE[2] = 0x01000000; /* nop */ \
GOT_BASE[3] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)) { \
case R_SPARC_32: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_GLOB_DAT: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_JMP_SLOT: \
REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
break; \
case R_SPARC_NONE: \
break; \
case R_SPARC_WDISP30: \
break; \
case R_SPARC_RELATIVE: \
*REL += (unsigned int) LOAD + (RELP)->r_addend; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done. The crt calls atexit with $g1 if not null, so we need to
* ensure that it contains NULL.
*/
#define START() \
__asm__ volatile ( \
"add %%g0,%%g0,%%g1\n\t" \
"jmpl %0, %%o7\n\t" \
"restore %%g0,%%g0,%%g0\n\t" \
: /*"=r" (status) */ : \
"r" (_dl_elf_main): "g1", "o0", "o1")
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_SPARC
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "Sparc"
#ifndef COMPILE_ASM
extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
unsigned int * i);
#endif
/*
* Define this if you want a dynamic loader that works on Solaris.
*/
#define SOLARIS_COMPATIBLE
/*
* Define this because we do not want to call .udiv in the library.
* Change on the plans -miguel:
* We just statically link against .udiv. This is required
* if we want to be able to run on Sun4c machines.
*/
/* We now link .urem against this one */
#ifdef USE_V8
#define do_rem(result,n,base) ({ \
volatile int __res; \
__asm__("mov %%g0,%%Y\n\t" \
"sdiv %2,%3,%%l6\n\t" \
"smul %%l6,%3,%%l6\n\t" \
"sub %2,%%l6,%0\n\t" \
:"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
#else
#define do_rem(a,b,c) a = _dl_urem (b,c);
#endif
/*
* dbx wants the binder to have a specific name. Mustn't disappoint it.
*/
#ifdef SOLARIS_COMPATIBLE
#define _dl_linux_resolve _elf_rtbndr
#endif

355
ldso/ldso/sparc/elfinterp.c Normal file
View File

@@ -0,0 +1,355 @@
/* Run an ELF binary on a linux system.
Copyright (C) 1995, Eric Youngdale.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef VERBOSE_DLINKER
#define VERBOSE_DLINKER
#endif
#ifdef VERBOSE_DLINKER
static char * _dl_reltypes[] = { "R_SPARC_NONE", "R_SPARC_8",
"R_SPARC_16", "R_SPARC_32", "R_SPARC_DISP8", "R_SPARC_DISP16",
"R_SPARC_DISP32", "R_SPARC_WDISP30", "R_SPARC_WDISP22",
"R_SPARC_HI22", "R_SPARC_22", "R_SPARC_13", "R_SPARC_LO10",
"R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", "R_SPARC_PC10",
"R_SPARC_PC22", "R_SPARC_WPLT30", "R_SPARC_COPY",
"R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", "R_SPARC_RELATIVE",
"R_SPARC_UA32"};
#endif
/* Program to load an ELF binary on a linux system, and run it.
References to symbols in sharable libraries can be resolved by either
an ELF sharable library or a linux style of shared library. */
/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
I ever taken any courses on internals. This program was developed using
information available through the book "UNIX SYSTEM V RELEASE 4,
Programmers guide: Ansi C and Programming Support Tools", which did
a more than adequate job of explaining everything required to get this
working. */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/unistd.h>
/*#include <stdlib.h>*/
#include "string.h"
#include <linux/unistd.h>
#include <linux/fcntl.h>
#include "hash.h"
#include "linuxelf.h"
#include "sysdep.h"
#include "../syscall.h"
#include "../string.h"
#define SVR4_COMPATIBILITY
extern char *_dl_progname;
extern _dl_linux_resolve(void);
unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
{
int reloc_type;
struct elf32_rela * this_reloc;
char * strtab;
struct elf32_sym * symtab;
struct elf32_rela * rel_addr;
struct elf_resolve * tpnt;
int symtab_index;
char * new_addr;
char ** got_addr;
unsigned int instr_addr;
tpnt = (struct elf_resolve *) plt[2];
rel_addr = (struct elf32_rela *) (tpnt->dynamic_info[DT_JMPREL] +
tpnt->loadaddr);
/*
* Generate the correct relocation index into the .rela.plt section.
*/
reloc_entry = (reloc_entry >> 12) - 0xc;
this_reloc = (struct elf32_rela *) ((char *) rel_addr + reloc_entry);
reloc_type = ELF32_R_TYPE(this_reloc->r_info);
symtab_index = ELF32_R_SYM(this_reloc->r_info);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
_dl_fdprintf(2, "tpnt = %x\n", tpnt);
_dl_fdprintf(2, "reloc = %x\n", this_reloc);
_dl_fdprintf(2, "symtab = %x\n", symtab);
_dl_fdprintf(2, "strtab = %x\n", strtab);
if (reloc_type != R_SPARC_JMP_SLOT) {
_dl_fdprintf(2, "%s: incorrect relocation type in jump relocations (%d)\n",
_dl_progname, reloc_type);
_dl_exit(30);
};
/* Address of jump instruction to fix up */
instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr);
got_addr = (char **) instr_addr;
_dl_fdprintf(2, "symtab_index %d\n", symtab_index);
#ifdef DEBUG
_dl_fdprintf(2, "Resolving symbol %s\n",
strtab + symtab[symtab_index].st_name);
#endif
/* Get the address of the GOT entry */
new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) got_addr, tpnt, 0);
if(!new_addr) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
_dl_exit(31);
};
/* #define DEBUG_LIBRARY */
#ifdef DEBUG_LIBRARY
if((unsigned int) got_addr < 0x40000000) {
_dl_fdprintf(2, "Calling library function: %s\n",
strtab + symtab[symtab_index].st_name);
} else {
got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
}
#else
got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
#endif
_dl_fdprintf(2, "Address = %x\n",new_addr);
_dl_exit(32);
return (unsigned int) new_addr;
}
void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type){
int i;
char * strtab;
int reloc_type;
int symtab_index;
struct elf32_sym * symtab;
struct elf32_rela * rpnt;
unsigned int * reloc_addr;
/* Now parse the relocation information */
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i += sizeof(struct elf32_rela), rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
/* When the dynamic linker bootstrapped itself, it resolved some symbols.
Make sure we do not do them again */
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index && tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
switch(reloc_type){
case R_SPARC_NONE:
break;
case R_SPARC_JMP_SLOT:
break;
default:
_dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
#endif
if(symtab_index) _dl_fdprintf(2, "'%s'\n",
strtab + symtab[symtab_index].st_name);
_dl_exit(33);
};
};
}
int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
int rel_size, int type){
int i;
char * strtab;
int reloc_type;
int goof = 0;
struct elf32_sym * symtab;
struct elf32_rela * rpnt;
unsigned int * reloc_addr;
unsigned int symbol_addr;
int symtab_index;
/* Now parse the relocation information */
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index) {
if(tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope, (int) reloc_addr,
(reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), 0);
if(!symbol_addr &&
ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
};
};
switch(reloc_type){
case R_SPARC_NONE:
break;
case R_SPARC_32:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
case R_SPARC_DISP32:
*reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
break;
case R_SPARC_GLOB_DAT:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
case R_SPARC_JMP_SLOT:
reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
break;
case R_SPARC_RELATIVE:
*reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
break;
case R_SPARC_HI22:
if (!symbol_addr)
symbol_addr = tpnt->loadaddr + rpnt->r_addend;
else
symbol_addr += rpnt->r_addend;
*reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
break;
case R_SPARC_LO10:
if (!symbol_addr)
symbol_addr = tpnt->loadaddr + rpnt->r_addend;
else
symbol_addr += rpnt->r_addend;
*reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
break;
case R_SPARC_WDISP30:
*reloc_addr = (*reloc_addr & 0xc0000000)|
((symbol_addr - (unsigned int) reloc_addr) >> 2);
break;
case R_SPARC_COPY:
#if 0 /* This one is done later */
_dl_fdprintf(2, "Doing copy for symbol ");
if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
_dl_fdprintf(2, "\n");
_dl_memcpy((void *) symtab[symtab_index].st_value,
(void *) symbol_addr,
symtab[symtab_index].st_size);
#endif
break;
default:
_dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
#ifdef VERBOSE_DLINKER
_dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
#endif
if (symtab_index)
_dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
_dl_exit(34);
};
};
return goof;
}
/* This is done as a separate step, because there are cases where
information is first copied and later initialized. This results in
the wrong information being copied. Someone at Sun was complaining about
a bug in the handling of _COPY by SVr4, and this may in fact be what he
was talking about. Sigh. */
/* No, there are cases where the SVr4 linker fails to emit COPY relocs
at all */
int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
int rel_size, int type)
{
int i;
char * strtab;
int reloc_type;
int goof = 0;
struct elf32_sym * symtab;
struct elf32_rela * rpnt;
unsigned int * reloc_addr;
unsigned int symbol_addr;
struct elf_resolve *tpnt;
int symtab_index;
/* Now parse the relocation information */
tpnt = xpnt->dyn;
rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
if(reloc_type != R_SPARC_COPY) continue;
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
if(!symtab_index && tpnt->libtype == program_interpreter) continue;
if(symtab_index) {
if(tpnt->libtype == program_interpreter &&
_dl_symbol(strtab + symtab[symtab_index].st_name))
continue;
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
xpnt->next, (int) reloc_addr, NULL, 1);
if(!symbol_addr) {
_dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
goof++;
};
};
if (!goof)
_dl_memcpy((char *) symtab[symtab_index].st_value,
(char *) symbol_addr,
symtab[symtab_index].st_size);
};
return goof;
}

131
ldso/ldso/sparc/ld_sysdep.h Normal file
View File

@@ -0,0 +1,131 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
#define LINUXBIN
/*
* Define this if the system uses RELOCA.
*/
#define ELF_USES_RELOCA
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here. We assume that argc is stored
* at the word just below the argvp that we return here.
*/
#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
/*
* Initialization sequence for a GOT. For the Sparc, this points to the
* PLT, and we need to initialize a couple of the slots. The PLT should
* look like:
*
* save %sp, -64, %sp
* call _dl_linux_resolve
* nop
* .word implementation_dependent
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
GOT_BASE[2] = 0x01000000; /* nop */ \
GOT_BASE[3] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)) { \
case R_SPARC_32: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_GLOB_DAT: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_JMP_SLOT: \
REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
break; \
case R_SPARC_NONE: \
break; \
case R_SPARC_WDISP30: \
break; \
case R_SPARC_RELATIVE: \
*REL += (unsigned int) LOAD + (RELP)->r_addend; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done. The crt calls atexit with $g1 if not null, so we need to
* ensure that it contains NULL.
*/
#define START() \
__asm__ volatile ( \
"add %%g0,%%g0,%%g1\n\t" \
"jmpl %0, %%o7\n\t" \
"restore %%g0,%%g0,%%g0\n\t" \
: /*"=r" (status) */ : \
"r" (_dl_elf_main): "g1", "o0", "o1")
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_SPARC
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "Sparc"
#ifndef COMPILE_ASM
extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
unsigned int * i);
#endif
/*
* Define this if you want a dynamic loader that works on Solaris.
*/
#define SOLARIS_COMPATIBLE
/*
* Define this because we do not want to call .udiv in the library.
* Change on the plans -miguel:
* We just statically link against .udiv. This is required
* if we want to be able to run on Sun4c machines.
*/
/* We now link .urem against this one */
#ifdef USE_V8
#define do_rem(result,n,base) ({ \
volatile int __res; \
__asm__("mov %%g0,%%Y\n\t" \
"sdiv %2,%3,%%l6\n\t" \
"smul %%l6,%3,%%l6\n\t" \
"sub %2,%%l6,%0\n\t" \
:"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
#else
#define do_rem(a,b,c) a = _dl_urem (b,c);
#endif
/*
* dbx wants the binder to have a specific name. Mustn't disappoint it.
*/
#ifdef SOLARIS_COMPATIBLE
#define _dl_linux_resolve _elf_rtbndr
#endif

25
ldso/ldso/sparc/resolve.S Normal file
View File

@@ -0,0 +1,25 @@
/*
* These are various helper routines that are needed to run an ELF image.
*/
#define COMPILE_ASM
#include "sysdep.h"
.text
.align 16
.globl _dl_linux_resolve
_dl_linux_resolve:
/*
* Call the resolver - pass the address of the PLT so that we can
* figure out which module we are in.
*/
mov %o7,%o1
call _dl_linux_resolver
mov %g1,%o0
jmpl %o0,%o7
restore
.LFE2:
.type _dl_linux_resolve,#function
.size _dl_linux_resolve,.LFE2-_dl_linux_resolve

369
ldso/ldso/sparc/sdiv.S Normal file
View File

@@ -0,0 +1,369 @@
/* This file is generated from divrem.m4; DO NOT EDIT! */
/*
* Division and remainder, from Appendix E of the Sparc Version 8
* Architecture Manual, with fixes from Gordon Irlam.
*/
/*
* Input: dividend and divisor in %o0 and %o1 respectively.
*
* m4 parameters:
* .div name of function to generate
* div div=div => %o0 / %o1; div=rem => %o0 % %o1
* true true=true => signed; true=false => unsigned
*
* Algorithm parameters:
* N how many bits per iteration we try to get (4)
* WORDSIZE total number of bits (32)
*
* Derived constants:
* TOPBITS number of bits in the top decade of a number
*
* Important variables:
* Q the partial quotient under development (initially 0)
* R the remainder so far, initially the dividend
* ITER number of main division loop iterations required;
* equal to ceil(log2(quotient) / N). Note that this
* is the log base (2^N) of the quotient.
* V the current comparand, initially divisor*2^(ITER*N-1)
*
* Cost:
* Current estimate for non-large dividend is
* ceil(log2(quotient) / N) * (10 + 7N/2) + C
* A large dividend is one greater than 2^(31-TOPBITS) and takes a
* different path, as the upper bits of the quotient must be developed
* one bit at a time.
*/
#include "DEFS.h"
#ifndef __linux__
#ifdef __svr4__
#include <sys/trap.h>
#else
#include "/usr/include/machine/trap.h"
#endif
#else
#include <asm/traps.h>
#endif
FUNC(_dl_div)
! compute sign of result; if neither is negative, no problem
orcc %o1, %o0, %g0 ! either negative?
bge 2f ! no, go do the divide
xor %o1, %o0, %g6 ! compute sign in any case
tst %o1
bge 1f
tst %o0
! %o1 is definitely negative; %o0 might also be negative
bge 2f ! if %o0 not negative...
sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
1: ! %o0 is negative, %o1 is nonnegative
sub %g0, %o0, %o0 ! make %o0 nonnegative
2:
! Ready to divide. Compute size of quotient; scale comparand.
orcc %o1, %g0, %o5
bne 1f
mov %o0, %o3
! Divide by zero trap. If it returns, return 0 (about as
! wrong as possible, but that is what SunOS does...).
ta ST_DIV0
retl
clr %o0
1:
cmp %o3, %o5 ! if %o1 exceeds %o0, done
blu Lgot_result ! (and algorithm fails otherwise)
clr %o2
sethi %hi(1 << (32 - 4 - 1)), %g1
cmp %o3, %g1
blu Lnot_really_big
clr %o4
! Here the dividend is >= 2**(31-N) or so. We must be careful here,
! as our usual N-at-a-shot divide step will cause overflow and havoc.
! The number of bits in the result here is N*ITER+SC, where SC <= N.
! Compute ITER in an unorthodox manner: know we need to shift V into
! the top decade: so do not even bother to compare to R.
1:
cmp %o5, %g1
bgeu 3f
mov 1, %g7
sll %o5, 4, %o5
b 1b
add %o4, 1, %o4
! Now compute %g7.
2: addcc %o5, %o5, %o5
bcc Lnot_too_big
add %g7, 1, %g7
! We get here if the %o1 overflowed while shifting.
! This means that %o3 has the high-order bit set.
! Restore %o5 and subtract from %o3.
sll %g1, 4, %g1 ! high order bit
srl %o5, 1, %o5 ! rest of %o5
add %o5, %g1, %o5
b Ldo_single_div
sub %g7, 1, %g7
Lnot_too_big:
3: cmp %o5, %o3
blu 2b
nop
be Ldo_single_div
nop
/* NB: these are commented out in the V8-Sparc manual as well */
/* (I do not understand this) */
! %o5 > %o3: went too far: back up 1 step
! srl %o5, 1, %o5
! dec %g7
! do single-bit divide steps
!
! We have to be careful here. We know that %o3 >= %o5, so we can do the
! first divide step without thinking. BUT, the others are conditional,
! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
! order bit set in the first step, just falling into the regular
! division loop will mess up the first time around.
! So we unroll slightly...
Ldo_single_div:
subcc %g7, 1, %g7
bl Lend_regular_divide
nop
sub %o3, %o5, %o3
mov 1, %o2
b Lend_single_divloop
nop
Lsingle_divloop:
sll %o2, 1, %o2
bl 1f
srl %o5, 1, %o5
! %o3 >= 0
sub %o3, %o5, %o3
b 2f
add %o2, 1, %o2
1: ! %o3 < 0
add %o3, %o5, %o3
sub %o2, 1, %o2
2:
Lend_single_divloop:
subcc %g7, 1, %g7
bge Lsingle_divloop
tst %o3
b,a Lend_regular_divide
Lnot_really_big:
1:
sll %o5, 4, %o5
cmp %o5, %o3
bleu 1b
addcc %o4, 1, %o4
be Lgot_result
sub %o4, 1, %o4
tst %o3 ! set up for initial iteration
Ldivloop:
sll %o2, 4, %o2
! depth 1, accumulated bits 0
bl L.1.16
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 2, accumulated bits 1
bl L.2.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits 3
bl L.3.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 7
bl L.4.23
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (7*2+1), %o2
L.4.23:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (7*2-1), %o2
L.3.19:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 5
bl L.4.21
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (5*2+1), %o2
L.4.21:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (5*2-1), %o2
L.2.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits 1
bl L.3.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 3
bl L.4.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (3*2+1), %o2
L.4.19:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (3*2-1), %o2
L.3.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 1
bl L.4.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (1*2+1), %o2
L.4.17:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (1*2-1), %o2
L.1.16:
! remainder is negative
addcc %o3,%o5,%o3
! depth 2, accumulated bits -1
bl L.2.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits -1
bl L.3.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -1
bl L.4.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-1*2+1), %o2
L.4.15:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-1*2-1), %o2
L.3.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -3
bl L.4.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-3*2+1), %o2
L.4.13:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-3*2-1), %o2
L.2.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits -3
bl L.3.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -5
bl L.4.11
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-5*2+1), %o2
L.4.11:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-5*2-1), %o2
L.3.13:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -7
bl L.4.9
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-7*2+1), %o2
L.4.9:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-7*2-1), %o2
9:
Lend_regular_divide:
subcc %o4, 1, %o4
bge Ldivloop
tst %o3
bl,a Lgot_result
! non-restoring fixup here (one instruction only!)
sub %o2, 1, %o2
Lgot_result:
! check to see if answer should be < 0
tst %g6
bl,a 1f
sub %g0, %o2, %o2
1:
retl
mov %o2, %o0

131
ldso/ldso/sparc/sysdep.h Normal file
View File

@@ -0,0 +1,131 @@
/*
* Various assmbly language/system dependent hacks that are required
* so that we can minimize the amount of platform specific code.
*/
#define LINUXBIN
/*
* Define this if the system uses RELOCA.
*/
#define ELF_USES_RELOCA
/*
* Get the address of the Global offset table. This must be absolute, not
* relative.
*/
#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
/*
* Get a pointer to the argv array. On many platforms this can be just
* the address if the first argument, on other platforms we need to
* do something a little more subtle here. We assume that argc is stored
* at the word just below the argvp that we return here.
*/
#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
/*
* Initialization sequence for a GOT. For the Sparc, this points to the
* PLT, and we need to initialize a couple of the slots. The PLT should
* look like:
*
* save %sp, -64, %sp
* call _dl_linux_resolve
* nop
* .word implementation_dependent
*/
#define INIT_GOT(GOT_BASE,MODULE) \
{ \
GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
GOT_BASE[2] = 0x01000000; /* nop */ \
GOT_BASE[3] = (int) MODULE; \
}
/*
* Here is a macro to perform a relocation. This is only used when
* bootstrapping the dynamic loader.
*/
#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
switch(ELF32_R_TYPE((RELP)->r_info)) { \
case R_SPARC_32: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_GLOB_DAT: \
*REL = SYMBOL + (RELP)->r_addend; \
break; \
case R_SPARC_JMP_SLOT: \
REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
break; \
case R_SPARC_NONE: \
break; \
case R_SPARC_WDISP30: \
break; \
case R_SPARC_RELATIVE: \
*REL += (unsigned int) LOAD + (RELP)->r_addend; \
break; \
default: \
_dl_exit(1); \
}
/*
* Transfer control to the user's application, once the dynamic loader
* is done. The crt calls atexit with $g1 if not null, so we need to
* ensure that it contains NULL.
*/
#define START() \
__asm__ volatile ( \
"add %%g0,%%g0,%%g1\n\t" \
"jmpl %0, %%o7\n\t" \
"restore %%g0,%%g0,%%g0\n\t" \
: /*"=r" (status) */ : \
"r" (_dl_elf_main): "g1", "o0", "o1")
/* Here we define the magic numbers that this dynamic loader should accept */
#define MAGIC1 EM_SPARC
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "Sparc"
#ifndef COMPILE_ASM
extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
unsigned int * i);
#endif
/*
* Define this if you want a dynamic loader that works on Solaris.
*/
#define SOLARIS_COMPATIBLE
/*
* Define this because we do not want to call .udiv in the library.
* Change on the plans -miguel:
* We just statically link against .udiv. This is required
* if we want to be able to run on Sun4c machines.
*/
/* We now link .urem against this one */
#ifdef USE_V8
#define do_rem(result,n,base) ({ \
volatile int __res; \
__asm__("mov %%g0,%%Y\n\t" \
"sdiv %2,%3,%%l6\n\t" \
"smul %%l6,%3,%%l6\n\t" \
"sub %2,%%l6,%0\n\t" \
:"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
#else
#define do_rem(a,b,c) a = _dl_urem (b,c);
#endif
/*
* dbx wants the binder to have a specific name. Mustn't disappoint it.
*/
#ifdef SOLARIS_COMPATIBLE
#define _dl_linux_resolve _elf_rtbndr
#endif

351
ldso/ldso/sparc/udiv.S Normal file
View File

@@ -0,0 +1,351 @@
/* This file is generated from divrem.m4; DO NOT EDIT! */
/*
* Division and remainder, from Appendix E of the Sparc Version 8
* Architecture Manual, with fixes from Gordon Irlam.
*/
/*
* Input: dividend and divisor in %o0 and %o1 respectively.
*
* m4 parameters:
* .udiv name of function to generate
* div div=div => %o0 / %o1; div=rem => %o0 % %o1
* false false=true => signed; false=false => unsigned
*
* Algorithm parameters:
* N how many bits per iteration we try to get (4)
* WORDSIZE total number of bits (32)
*
* Derived constants:
* TOPBITS number of bits in the top decade of a number
*
* Important variables:
* Q the partial quotient under development (initially 0)
* R the remainder so far, initially the dividend
* ITER number of main division loop iterations required;
* equal to ceil(log2(quotient) / N). Note that this
* is the log base (2^N) of the quotient.
* V the current comparand, initially divisor*2^(ITER*N-1)
*
* Cost:
* Current estimate for non-large dividend is
* ceil(log2(quotient) / N) * (10 + 7N/2) + C
* A large dividend is one greater than 2^(31-TOPBITS) and takes a
* different path, as the upper bits of the quotient must be developed
* one bit at a time.
*/
#include "DEFS.h"
#ifndef __linux__
#ifdef __svr4__
#include <sys/trap.h>
#else
#include "/usr/include/machine/trap.h"
#endif
#else
#include <asm/traps.h>
#endif
FUNC(_dl_udiv)
! Ready to divide. Compute size of quotient; scale comparand.
orcc %o1, %g0, %o5
bne 1f
mov %o0, %o3
! Divide by zero trap. If it returns, return 0 (about as
! wrong as possible, but that is what SunOS does...).
ta ST_DIV0
retl
clr %o0
1:
cmp %o3, %o5 ! if %o1 exceeds %o0, done
blu Lgot_result ! (and algorithm fails otherwise)
clr %o2
sethi %hi(1 << (32 - 4 - 1)), %g1
cmp %o3, %g1
blu Lnot_really_big
clr %o4
! Here the dividend is >= 2**(31-N) or so. We must be careful here,
! as our usual N-at-a-shot divide step will cause overflow and havoc.
! The number of bits in the result here is N*ITER+SC, where SC <= N.
! Compute ITER in an unorthodox manner: know we need to shift V into
! the top decade: so do not even bother to compare to R.
1:
cmp %o5, %g1
bgeu 3f
mov 1, %g7
sll %o5, 4, %o5
b 1b
add %o4, 1, %o4
! Now compute %g7.
2: addcc %o5, %o5, %o5
bcc Lnot_too_big
add %g7, 1, %g7
! We get here if the %o1 overflowed while shifting.
! This means that %o3 has the high-order bit set.
! Restore %o5 and subtract from %o3.
sll %g1, 4, %g1 ! high order bit
srl %o5, 1, %o5 ! rest of %o5
add %o5, %g1, %o5
b Ldo_single_div
sub %g7, 1, %g7
Lnot_too_big:
3: cmp %o5, %o3
blu 2b
nop
be Ldo_single_div
nop
/* NB: these are commented out in the V8-Sparc manual as well */
/* (I do not understand this) */
! %o5 > %o3: went too far: back up 1 step
! srl %o5, 1, %o5
! dec %g7
! do single-bit divide steps
!
! We have to be careful here. We know that %o3 >= %o5, so we can do the
! first divide step without thinking. BUT, the others are conditional,
! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
! order bit set in the first step, just falling into the regular
! division loop will mess up the first time around.
! So we unroll slightly...
Ldo_single_div:
subcc %g7, 1, %g7
bl Lend_regular_divide
nop
sub %o3, %o5, %o3
mov 1, %o2
b Lend_single_divloop
nop
Lsingle_divloop:
sll %o2, 1, %o2
bl 1f
srl %o5, 1, %o5
! %o3 >= 0
sub %o3, %o5, %o3
b 2f
add %o2, 1, %o2
1: ! %o3 < 0
add %o3, %o5, %o3
sub %o2, 1, %o2
2:
Lend_single_divloop:
subcc %g7, 1, %g7
bge Lsingle_divloop
tst %o3
b,a Lend_regular_divide
Lnot_really_big:
1:
sll %o5, 4, %o5
cmp %o5, %o3
bleu 1b
addcc %o4, 1, %o4
be Lgot_result
sub %o4, 1, %o4
tst %o3 ! set up for initial iteration
Ldivloop:
sll %o2, 4, %o2
! depth 1, accumulated bits 0
bl L.1.16
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 2, accumulated bits 1
bl L.2.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits 3
bl L.3.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 7
bl L.4.23
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (7*2+1), %o2
L.4.23:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (7*2-1), %o2
L.3.19:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 5
bl L.4.21
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (5*2+1), %o2
L.4.21:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (5*2-1), %o2
L.2.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits 1
bl L.3.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 3
bl L.4.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (3*2+1), %o2
L.4.19:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (3*2-1), %o2
L.3.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 1
bl L.4.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (1*2+1), %o2
L.4.17:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (1*2-1), %o2
L.1.16:
! remainder is negative
addcc %o3,%o5,%o3
! depth 2, accumulated bits -1
bl L.2.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits -1
bl L.3.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -1
bl L.4.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-1*2+1), %o2
L.4.15:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-1*2-1), %o2
L.3.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -3
bl L.4.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-3*2+1), %o2
L.4.13:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-3*2-1), %o2
L.2.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits -3
bl L.3.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -5
bl L.4.11
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-5*2+1), %o2
L.4.11:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-5*2-1), %o2
L.3.13:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -7
bl L.4.9
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-7*2+1), %o2
L.4.9:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-7*2-1), %o2
9:
Lend_regular_divide:
subcc %o4, 1, %o4
bge Ldivloop
tst %o3
bl,a Lgot_result
! non-restoring fixup here (one instruction only!)
sub %o2, 1, %o2
Lgot_result:
retl
mov %o2, %o0

153
ldso/ldso/sparc/umul.S Normal file
View File

@@ -0,0 +1,153 @@
/*
* Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
* upper 32 bits of the 64-bit product).
*
* This code optimizes short (less than 13-bit) multiplies. Short
* multiplies require 25 instruction cycles, and long ones require
* 45 instruction cycles.
*
* On return, overflow has occurred (%o1 is not zero) if and only if
* the Z condition code is clear, allowing, e.g., the following:
*
* call .umul
* nop
* bnz overflow (or tnz)
*/
#include "DEFS.h"
FUNC(.umul)
or %o0, %o1, %o4
mov %o0, %y ! multiplier -> Y
andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args
be Lmul_shortway ! if zero, can do it the short way
andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
/*
* Long multiply. 32 steps, followed by a final shift step.
*/
mulscc %o4, %o1, %o4 ! 1
mulscc %o4, %o1, %o4 ! 2
mulscc %o4, %o1, %o4 ! 3
mulscc %o4, %o1, %o4 ! 4
mulscc %o4, %o1, %o4 ! 5
mulscc %o4, %o1, %o4 ! 6
mulscc %o4, %o1, %o4 ! 7
mulscc %o4, %o1, %o4 ! 8
mulscc %o4, %o1, %o4 ! 9
mulscc %o4, %o1, %o4 ! 10
mulscc %o4, %o1, %o4 ! 11
mulscc %o4, %o1, %o4 ! 12
mulscc %o4, %o1, %o4 ! 13
mulscc %o4, %o1, %o4 ! 14
mulscc %o4, %o1, %o4 ! 15
mulscc %o4, %o1, %o4 ! 16
mulscc %o4, %o1, %o4 ! 17
mulscc %o4, %o1, %o4 ! 18
mulscc %o4, %o1, %o4 ! 19
mulscc %o4, %o1, %o4 ! 20
mulscc %o4, %o1, %o4 ! 21
mulscc %o4, %o1, %o4 ! 22
mulscc %o4, %o1, %o4 ! 23
mulscc %o4, %o1, %o4 ! 24
mulscc %o4, %o1, %o4 ! 25
mulscc %o4, %o1, %o4 ! 26
mulscc %o4, %o1, %o4 ! 27
mulscc %o4, %o1, %o4 ! 28
mulscc %o4, %o1, %o4 ! 29
mulscc %o4, %o1, %o4 ! 30
mulscc %o4, %o1, %o4 ! 31
mulscc %o4, %o1, %o4 ! 32
mulscc %o4, %g0, %o4 ! final shift
/*
* Normally, with the shift-and-add approach, if both numbers are
* positive you get the correct result. With 32-bit two's-complement
* numbers, -x is represented as
*
* x 32
* ( 2 - ------ ) mod 2 * 2
* 32
* 2
*
* (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s,
* we can treat this as if the radix point were just to the left
* of the sign bit (multiply by 2^32), and get
*
* -x = (2 - x) mod 2
*
* Then, ignoring the `mod 2's for convenience:
*
* x * y = xy
* -x * y = 2y - xy
* x * -y = 2x - xy
* -x * -y = 4 - 2x - 2y + xy
*
* For signed multiplies, we subtract (x << 32) from the partial
* product to fix this problem for negative multipliers (see mul.s).
* Because of the way the shift into the partial product is calculated
* (N xor V), this term is automatically removed for the multiplicand,
* so we don't have to adjust.
*
* But for unsigned multiplies, the high order bit wasn't a sign bit,
* and the correction is wrong. So for unsigned multiplies where the
* high order bit is one, we end up with xy - (y << 32). To fix it
* we add y << 32.
*/
#if 0
tst %o1
bl,a 1f ! if %o1 < 0 (high order bit = 1),
add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half)
1: rd %y, %o0 ! get lower half of product
retl
addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0
#else
/* Faster code from tege@sics.se. */
sra %o1, 31, %o2 ! make mask from sign bit
and %o0, %o2, %o2 ! %o2 = 0 or %o0, depending on sign of %o1
rd %y, %o0 ! get lower half of product
retl
addcc %o4, %o2, %o1 ! add compensation and put upper half in place
#endif
Lmul_shortway:
/*
* Short multiply. 12 steps, followed by a final shift step.
* The resulting bits are off by 12 and (32-12) = 20 bit positions,
* but there is no problem with %o0 being negative (unlike above),
* and overflow is impossible (the answer is at most 24 bits long).
*/
mulscc %o4, %o1, %o4 ! 1
mulscc %o4, %o1, %o4 ! 2
mulscc %o4, %o1, %o4 ! 3
mulscc %o4, %o1, %o4 ! 4
mulscc %o4, %o1, %o4 ! 5
mulscc %o4, %o1, %o4 ! 6
mulscc %o4, %o1, %o4 ! 7
mulscc %o4, %o1, %o4 ! 8
mulscc %o4, %o1, %o4 ! 9
mulscc %o4, %o1, %o4 ! 10
mulscc %o4, %o1, %o4 ! 11
mulscc %o4, %o1, %o4 ! 12
mulscc %o4, %g0, %o4 ! final shift
/*
* %o4 has 20 of the bits that should be in the result; %y has
* the bottom 12 (as %y's top 12). That is:
*
* %o4 %y
* +----------------+----------------+
* | -12- | -20- | -12- | -20- |
* +------(---------+------)---------+
* -----result-----
*
* The 12 bits of %o4 left of the `result' area are all zero;
* in fact, all top 20 bits of %o4 are zero.
*/
rd %y, %o5
sll %o4, 12, %o0 ! shift middle bits left 12
srl %o5, 20, %o5 ! shift low bits right 20
or %o5, %o0, %o0
retl
addcc %g0, %g0, %o1 ! %o1 = zero, and set Z

352
ldso/ldso/sparc/urem.S Normal file
View File

@@ -0,0 +1,352 @@
/* This file is generated from divrem.m4; DO NOT EDIT! */
/*
* Division and remainder, from Appendix E of the Sparc Version 8
* Architecture Manual, with fixes from Gordon Irlam.
*/
/*
* Input: dividend and divisor in %o0 and %o1 respectively.
*
* m4 parameters:
* .urem name of function to generate
* rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1
* false false=true => signed; false=false => unsigned
*
* Algorithm parameters:
* N how many bits per iteration we try to get (4)
* WORDSIZE total number of bits (32)
*
* Derived constants:
* TOPBITS number of bits in the top decade of a number
*
* Important variables:
* Q the partial quotient under development (initially 0)
* R the remainder so far, initially the dividend
* ITER number of main division loop iterations required;
* equal to ceil(log2(quotient) / N). Note that this
* is the log base (2^N) of the quotient.
* V the current comparand, initially divisor*2^(ITER*N-1)
*
* Cost:
* Current estimate for non-large dividend is
* ceil(log2(quotient) / N) * (10 + 7N/2) + C
* A large dividend is one greater than 2^(31-TOPBITS) and takes a
* different path, as the upper bits of the quotient must be developed
* one bit at a time.
*/
#include "DEFS.h"
#ifdef __linux__
#include <asm/traps.h>
#else
#ifdef __svr4__
#include <sys/trap.h>
#else
#include "/usr/include/machine/trap.h"
#endif
#endif
FUNC(_dl_urem)
! Ready to divide. Compute size of quotient; scale comparand.
orcc %o1, %g0, %o5
bne 1f
mov %o0, %o3
! Divide by zero trap. If it returns, return 0 (about as
! wrong as possible, but that is what SunOS does...).
ta ST_DIV0
retl
clr %o0
1:
cmp %o3, %o5 ! if %o1 exceeds %o0, done
blu Lgot_result ! (and algorithm fails otherwise)
clr %o2
sethi %hi(1 << (32 - 4 - 1)), %g1
cmp %o3, %g1
blu Lnot_really_big
clr %o4
! Here the dividend is >= 2**(31-N) or so. We must be careful here,
! as our usual N-at-a-shot divide step will cause overflow and havoc.
! The number of bits in the result here is N*ITER+SC, where SC <= N.
! Compute ITER in an unorthodox manner: know we need to shift V into
! the top decade: so do not even bother to compare to R.
1:
cmp %o5, %g1
bgeu 3f
mov 1, %g7
sll %o5, 4, %o5
b 1b
add %o4, 1, %o4
! Now compute %g7.
2: addcc %o5, %o5, %o5
bcc Lnot_too_big
add %g7, 1, %g7
! We get here if the %o1 overflowed while shifting.
! This means that %o3 has the high-order bit set.
! Restore %o5 and subtract from %o3.
sll %g1, 4, %g1 ! high order bit
srl %o5, 1, %o5 ! rest of %o5
add %o5, %g1, %o5
b Ldo_single_div
sub %g7, 1, %g7
Lnot_too_big:
3: cmp %o5, %o3
blu 2b
nop
be Ldo_single_div
nop
/* NB: these are commented out in the V8-Sparc manual as well */
/* (I do not understand this) */
! %o5 > %o3: went too far: back up 1 step
! srl %o5, 1, %o5
! dec %g7
! do single-bit divide steps
!
! We have to be careful here. We know that %o3 >= %o5, so we can do the
! first divide step without thinking. BUT, the others are conditional,
! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
! order bit set in the first step, just falling into the regular
! division loop will mess up the first time around.
! So we unroll slightly...
Ldo_single_div:
subcc %g7, 1, %g7
bl Lend_regular_divide
nop
sub %o3, %o5, %o3
mov 1, %o2
b Lend_single_divloop
nop
Lsingle_divloop:
sll %o2, 1, %o2
bl 1f
srl %o5, 1, %o5
! %o3 >= 0
sub %o3, %o5, %o3
b 2f
add %o2, 1, %o2
1: ! %o3 < 0
add %o3, %o5, %o3
sub %o2, 1, %o2
2:
Lend_single_divloop:
subcc %g7, 1, %g7
bge Lsingle_divloop
tst %o3
b,a Lend_regular_divide
Lnot_really_big:
1:
sll %o5, 4, %o5
cmp %o5, %o3
bleu 1b
addcc %o4, 1, %o4
be Lgot_result
sub %o4, 1, %o4
tst %o3 ! set up for initial iteration
Ldivloop:
sll %o2, 4, %o2
! depth 1, accumulated bits 0
bl L.1.16
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 2, accumulated bits 1
bl L.2.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits 3
bl L.3.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 7
bl L.4.23
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (7*2+1), %o2
L.4.23:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (7*2-1), %o2
L.3.19:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 5
bl L.4.21
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (5*2+1), %o2
L.4.21:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (5*2-1), %o2
L.2.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits 1
bl L.3.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits 3
bl L.4.19
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (3*2+1), %o2
L.4.19:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (3*2-1), %o2
L.3.17:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits 1
bl L.4.17
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (1*2+1), %o2
L.4.17:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (1*2-1), %o2
L.1.16:
! remainder is negative
addcc %o3,%o5,%o3
! depth 2, accumulated bits -1
bl L.2.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 3, accumulated bits -1
bl L.3.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -1
bl L.4.15
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-1*2+1), %o2
L.4.15:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-1*2-1), %o2
L.3.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -3
bl L.4.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-3*2+1), %o2
L.4.13:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-3*2-1), %o2
L.2.15:
! remainder is negative
addcc %o3,%o5,%o3
! depth 3, accumulated bits -3
bl L.3.13
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
! depth 4, accumulated bits -5
bl L.4.11
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-5*2+1), %o2
L.4.11:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-5*2-1), %o2
L.3.13:
! remainder is negative
addcc %o3,%o5,%o3
! depth 4, accumulated bits -7
bl L.4.9
srl %o5,1,%o5
! remainder is positive
subcc %o3,%o5,%o3
b 9f
add %o2, (-7*2+1), %o2
L.4.9:
! remainder is negative
addcc %o3,%o5,%o3
b 9f
add %o2, (-7*2-1), %o2
9:
Lend_regular_divide:
subcc %o4, 1, %o4
bge Ldivloop
tst %o3
bl,a Lgot_result
! non-restoring fixup here (one instruction only!)
add %o3, %o1, %o3
Lgot_result:
retl
mov %o3, %o0

112
ldso/ldso/string.h Normal file
View File

@@ -0,0 +1,112 @@
#ifndef _LINUX_STRING_H_
#define _LINUX_STRING_H_
#include <linux/types.h> /* for size_t */
#ifndef NULL
#define NULL ((void *) 0)
#endif
extern inline char * _dl_strcpy(char * dst,const char *src)
{
register char *ptr = dst;
while (*src)
*dst++ = *src++;
*dst = '\0';
return ptr;
}
extern inline int _dl_strcmp(const char * s1,const char * s2)
{
unsigned register char c1, c2;
do {
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0')
return c1 - c2;
}
while (c1 == c2);
return c1 - c2;
}
extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
{
unsigned register char c1 = '\0';
unsigned register char c2 = '\0';
while (len > 0) {
c1 = (unsigned char) *s1++;
c2 = (unsigned char) *s2++;
if (c1 == '\0' || c1 != c2)
return c1 - c2;
len--;
}
return c1 - c2;
}
extern inline char * _dl_strchr(const char * str,int c)
{
register char ch;
do {
if ((ch = *str) == c)
return (char *) str;
str++;
}
while (ch);
return 0;
}
extern inline size_t _dl_strlen(const char * str)
{
register char *ptr = (char *) str;
while (*ptr)
ptr++;
return (ptr - str);
}
extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
{
register char *a = dst;
register const char *b = src;
while (len--)
*a++ = *b++;
return dst;
}
extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
{
unsigned char *c1 = (unsigned char *)s1;
unsigned char *c2 = (unsigned char *)s2;
while (len--) {
if (*c1 != *c2)
return *c1 - *c2;
c1++;
c2++;
}
return 0;
}
extern inline void * _dl_memset(void * str,int c,size_t len)
{
register char *a = str;
while (len--)
*a++ = c;
return str;
}
#endif

108
ldso/ldso/syscall.h Normal file
View File

@@ -0,0 +1,108 @@
#include <linux/types.h>
#include <asm/unistd.h>
#ifndef _dl_MAX_ERRNO
#define _dl_MAX_ERRNO 4096
#endif
#define _dl_mmap_check_error(__res) \
(((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
/* Here are the definitions for some syscalls that are used
by the dynamic linker. The idea is that we want to be able
to call these before the errno symbol is dynamicly linked, so
we use our own version here. Note that we cannot assume any
dynamic linking at all, so we cannot return any error codes.
We just punt if there is an error. */
/* Do not include unistd.h, so gcc doesn't whine about
* _exit returning. It really doesn't return... */
#define __NR__dl_exit __NR_exit
static inline _syscall1(void, _dl_exit, int, status);
#define __NR__dl_close __NR_close
static inline _syscall1(int, _dl_close, int, fd);
#define __NR__dl_mmap_real __NR_mmap
static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long buffer[6];
buffer[0] = (unsigned long) addr;
buffer[1] = (unsigned long) size;
buffer[2] = (unsigned long) prot;
buffer[3] = (unsigned long) flags;
buffer[4] = (unsigned long) fd;
buffer[5] = (unsigned long) offset;
return (void *) _dl_mmap_real(buffer);
}
#define __NR__dl_open __NR_open
static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
#define __NR__dl_write __NR_write
static inline _syscall3(unsigned long, _dl_write, int, fd,
const void *, buf, unsigned long, count);
#define __NR__dl_read __NR_read
static inline _syscall3(unsigned long, _dl_read, int, fd,
const void *, buf, unsigned long, count);
#define __NR__dl_mprotect __NR_mprotect
static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
/* Pull in whatever this particular arch's kernel thinks the kernel version of
* struct stat should look like. It turns out that each arch has a different
* opinion on the subject, and different kernel revs use different names... */
#define __NR__dl_stat __NR_stat
#define stat kernel_stat
#define new_stat kernel_stat
#include <asm/stat.h>
#undef new_stat
#undef stat
static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
#define __NR__dl_munmap __NR_munmap
static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
#define __NR__dl_getuid __NR_getuid
static inline _syscall0(gid_t, _dl_getuid);
#define __NR__dl_geteuid __NR_geteuid
static inline _syscall0(uid_t, _dl_geteuid);
#define __NR__dl_getgid __NR_getgid
static inline _syscall0(gid_t, _dl_getgid);
#define __NR__dl_getegid __NR_getegid
static inline _syscall0(gid_t, _dl_getegid);
/*
* Not an actual syscall, but we need something in assembly to say whether
* this is OK or not.
*/
extern inline int _dl_suid_ok(void)
{
uid_t uid, euid, gid, egid;
uid = _dl_getuid();
euid = _dl_geteuid();
gid = _dl_getgid();
egid = _dl_getegid();
if(uid == euid && gid == egid)
return 1;
else
return 0;
}

290
ldso/ldso/vsprintf.c Normal file
View File

@@ -0,0 +1,290 @@
/*
* vsprintf.c
*
* Copyright (C) 1991-1996 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
#include <stdarg.h>
#include "string.h"
#include "hash.h"
#include <linux/unistd.h>
#include "syscall.h"
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
static int skip_atoi(const char **s)
{
int i=0;
while (is_digit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#ifndef __sparc__
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
#else
#define do_div(n,base) _dl_div ((n)/(base))
#define do_div(n,base) ({ \
int __res; \
__res = _dl_urem(((unsigned long) n),(unsigned) base); \
n = _dl_udiv(((unsigned long) n),(unsigned) base); \
__res; })
#endif
#define ADD_CHAR(s,n,c) ( ((n) > 1) ? *(s)++ = (c), (n)-- : (c) )
static char * number(char * str, int *bufsize, long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
ADD_CHAR(str, *bufsize, ' ');
if (sign)
ADD_CHAR(str, *bufsize, sign);
if (type & SPECIAL) {
if (base==8)
ADD_CHAR(str, *bufsize, '0');
else if (base==16) {
ADD_CHAR(str, *bufsize, '0');
ADD_CHAR(str, *bufsize, digits[33]);
}
}
if (!(type & LEFT))
while (size-- > 0)
ADD_CHAR(str, *bufsize, c);
while (i < precision--)
ADD_CHAR(str, *bufsize, '0');
while (i-- > 0)
ADD_CHAR(str, *bufsize, tmp[i]);
while (size-- > 0)
ADD_CHAR(str, *bufsize, ' ');
return str;
}
int _dl_fdprintf(int fd, const char *fmt, ...)
{
int len;
unsigned long num;
int i, base;
char * str;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
int bufsize;
char buf[2048];
va_list(args);
va_start(args, fmt);
for (str=buf, bufsize=sizeof buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
ADD_CHAR(str, bufsize, *fmt);
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
ADD_CHAR(str, bufsize, ' ');
ADD_CHAR(str, bufsize, (unsigned char) va_arg(args, int));
while (--field_width > 0)
ADD_CHAR(str, bufsize, ' ');
continue;
case 's':
s = va_arg(args, char *);
if (!s)
s = "<NULL>";
len = _dl_strlen(s);
if (!(flags & LEFT))
while (len < field_width--)
ADD_CHAR(str, bufsize, ' ');
for (i = 0; i < len; ++i)
ADD_CHAR(str, bufsize, *s++);
while (len < field_width--)
ADD_CHAR(str, bufsize, ' ');
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
str = number(str, &bufsize,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
if (*fmt != '%')
ADD_CHAR(str, bufsize, '%');
if (*fmt)
ADD_CHAR(str, bufsize, *fmt);
else
--fmt;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h')
if (flags & SIGN)
num = va_arg(args, short);
else
num = va_arg(args, unsigned short);
else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = number(str, &bufsize, num, base, field_width, precision, flags);
}
*str = '\0';
_dl_write(fd, buf, str-buf);
return str-buf;
}

31
ldso/libdl/Makefile Normal file
View File

@@ -0,0 +1,31 @@
TOPDIR=../../../
include $(TOPDIR)Rules.mak
include $(TOPDIR)/ld.so-1/Config.mk
CFLAGS += -DNO_UNDERSCORE -DVERBOSE_DLINKER -DUSE_CACHE
CFLAGS += #-fPIC -D__PIC__ #-funroll-loops
LIBDL = libdl.so
CSRC= dlib.c
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
$(COBJS): %.o : %.c
$(CC) -I.. -I../$(TARGET_ARCH) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
ELF_LDFLAGS=--shared -nostartfiles -nostdlib # using GNU ld
#ELF_LDFLAGS=-G # with SVr4 ld
lib:: $(OBJS)
$(CC) $(ELF_LDFLAGS) -o $(LIBDL).$(LDSO_VMAJOR) \
-Wl,-soname -Wl,$(LIBDL).$(LDSO_VMAJOR) *.o -lc
obj: $(OBJS)
realclean::
$(RM) -f .depend $(LIBDL) core *.o *.a *.s *.i tmp_make foo *~
clean::
$(RM) -f $(LIBDL) core *.o *.a *.s *.i tmp_make foo *~

41
ldso/libdl/dlfcn.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef DLFCN_H
#define DLFCN_H
#include <features.h>
/*
* Various defines and so forth for the dynamic linker
*/
/* For dlopen () */
#define RTLD_LAZY 1
#define RTLD_NOW 2
#define RTLD_GLOBAL 0x100
/* For dlsym */
#define RTLD_NEXT ((void *)-1)
__BEGIN_DECLS
/* The usual prototypes. We use void * instead of the actual
* datatype - the user does not manipulate the handles at all.
*/
extern void * dlopen __P((__const char * __filename, int __flag));
extern __const char * dlerror __P((void));
extern void * dlsym __P((void *, __const char *));
extern int dlclose __P((void *));
typedef struct
{
const char * dli_fname; /* filename */
void * dli_fbase; /* base address of object */
const char * dli_sname; /* nearest symbol name */
void * dli_saddr; /* nearest symbol address */
} Dl_info;
extern int dladdr __P((void * __address, Dl_info * __dlip ));
__END_DECLS
#endif

648
ldso/libdl/dlib.c Normal file
View File

@@ -0,0 +1,648 @@
/*
* libdl.c
*
* Functions required for dlopen et. al.
*/
#include "dlfcn.h"
/* #include "link.h" */
#include <stdlib.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "sysdep.h"
#include "syscall.h"
#include "hash.h"
#include "string.h"
#include "linuxelf.h"
extern int _dl_error_number;
extern struct r_debug * _dl_debug_addr;
extern void * (*_dl_malloc_function)(size_t size);
static int do_fixup(struct elf_resolve * tpnt, int flag);
static int do_dlclose(void *, int need_fini);
void * _dlopen(char * filename, int flag);
const char * _dlerror(void);
void * _dlsym(void *, char *);
int _dlclose(void *);
int _dladdr(void * __address, Dl_info * __dlip );
static const char * dl_error_names[] = {
"",
"File not found",
"Unable to open /dev/zero",
"Not an ELF file",
#if defined (__i386__)
"Not i386 binary",
#elif defined (__sparc__)
"Not sparc binary",
#elif defined (__mc68000__)
"Not m68k binary",
#else
"Unrecognized binary type",
#endif
"Not an ELF shared library",
"Unable to mmap file",
"No dynamic section",
#ifdef ELF_USES_RELOCA
"Unable to process REL relocs",
#else
"Unable to process RELA relocs",
#endif
"Bad handle",
"Unable to resolve symbol"
};
static void dl_cleanup(void) __attribute__ ((destructor));
static void dl_cleanup(void)
{
struct dyn_elf* d;
for (d = _dl_handles; d; d = d->next_handle)
if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI])
{
(*((int(*)(void))(d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI])))();
d->dyn->dynamic_info[DT_FINI] = 0;
}
}
void * _dlopen(char * libname, int flag)
{
struct elf_resolve * tpnt, *tfrom;
struct dyn_elf * rpnt;
struct dyn_elf * dyn_chain;
struct dyn_elf * dpnt;
static int dl_init = 0;
char * from;
void (*dl_brk)(void);
int (*dl_elf_init)(void);
from = __builtin_return_address(0);
/* Have the dynamic linker use the regular malloc function now */
if (!dl_init) {
dl_init++;
_dl_malloc_function = malloc;
}
/* Cover the trivial case first */
if (!libname) return _dl_symbol_tables;
#ifdef USE_CACHE
_dl_map_cache();
#endif
/*
* Try and locate the module we were called from - we
* need this so that we get the correct RPATH. Note that
* this is the current behavior under Solaris, but the
* ABI+ specifies that we should only use the RPATH from
* the application. Thus this may go away at some time
* in the future.
*/
tfrom = NULL;
for(dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next)
{
tpnt = dpnt->dyn;
if( tpnt->loadaddr < from
&& ( tfrom == NULL
|| tfrom->loadaddr < tpnt->loadaddr))
tfrom = tpnt;
}
if(!(tpnt = _dl_load_shared_library(0, tfrom, libname)))
{
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
return NULL;
}
tpnt->usage_count++;
dyn_chain = rpnt =
(struct dyn_elf *) malloc(sizeof(struct dyn_elf));
_dl_memset (rpnt, 0, sizeof(*rpnt));
rpnt->dyn = tpnt;
rpnt->flags = flag;
if (!tpnt->symbol_scope) tpnt->symbol_scope = dyn_chain;
rpnt->next_handle = _dl_handles;
_dl_handles = rpnt;
/*
* OK, we have the requested file in memory. Now check for
* any other requested files that may also be required.
*/
{
struct elf_resolve *tcurr;
struct elf_resolve * tpnt1;
struct dynamic * dpnt;
char * lpnt;
tcurr = tpnt;
do{
for(dpnt = (struct dynamic *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
{
if(dpnt->d_tag == DT_NEEDED)
{
lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
dpnt->d_un.d_val;
if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
goto oops;
rpnt->next =
(struct dyn_elf *) malloc(sizeof(struct dyn_elf));
_dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
rpnt = rpnt->next;
tpnt1->usage_count++;
if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
rpnt->dyn = tpnt1;
};
}
tcurr = tcurr->next;
} while(tcurr);
}
/*
* OK, now attach the entire chain at the end
*/
rpnt->next = _dl_symbol_tables;
if (do_fixup(tpnt, flag)) {
_dl_error_number = DL_NO_SYMBOL;
goto oops;
}
dl_brk = (void (*)()) _dl_debug_addr->r_brk;
if( dl_brk != NULL )
{
_dl_debug_addr->r_state = RT_ADD;
(*dl_brk)();
_dl_debug_addr->r_state = RT_CONSISTENT;
(*dl_brk)();
}
for(rpnt = dyn_chain; rpnt; rpnt = rpnt->next)
{
tpnt = rpnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
if (tpnt->libtype == elf_executable) continue;
if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
tpnt->init_flag |= INIT_FUNCS_CALLED;
if(tpnt->dynamic_info[DT_INIT]) {
dl_elf_init = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_INIT]);
(*dl_elf_init)();
}
}
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
return (void *) dyn_chain;
oops:
/* Something went wrong. Clean up and return NULL. */
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
do_dlclose (dyn_chain, 0);
return NULL;
}
static int do_fixup(struct elf_resolve * tpnt, int flag)
{
int goof = 0;
if(tpnt->next) goof += do_fixup(tpnt->next, flag);
if(tpnt->dynamic_info[DT_REL]) {
#ifdef ELF_USES_RELOCA
goof++;
#else
if (tpnt->init_flag & RELOCS_DONE) return goof;
tpnt->init_flag |= RELOCS_DONE;
goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
tpnt->dynamic_info[DT_RELSZ], 0);
#endif
}
if(tpnt->dynamic_info[DT_RELA]) {
#ifdef ELF_USES_RELOCA
if (tpnt->init_flag & RELOCS_DONE) return goof;
tpnt->init_flag |= RELOCS_DONE;
goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
tpnt->dynamic_info[DT_RELASZ], 0);
#else
goof++;
#endif
}
if(tpnt->dynamic_info[DT_JMPREL])
{
if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
tpnt->init_flag |= JMP_RELOCS_DONE;
if(flag == RTLD_LAZY)
_dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info[DT_PLTRELSZ], 0);
else
goof += _dl_parse_relocation_information(tpnt,
tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info[DT_PLTRELSZ], 0);
};
return goof;
}
void * _dlsym(void * vhandle, char * name)
{
struct elf_resolve * tpnt, *tfrom;
struct dyn_elf * handle;
char * from;
struct dyn_elf * rpnt;
void *ret;
handle = (struct dyn_elf *) vhandle;
/* First of all verify that we have a real handle
of some kind. Return NULL if not a valid handle. */
if (handle == NULL)
handle = _dl_symbol_tables;
else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
if (rpnt == handle) break;
if (!rpnt) {
_dl_error_number = DL_BAD_HANDLE;
return NULL;
}
}
else if (handle == RTLD_NEXT )
{
/*
* Try and locate the module we were called from - we
* need this so that we know where to start searching
* from. We never pass RTLD_NEXT down into the actual
* dynamic loader itself, as it doesn't know
* how to properly treat it.
*/
from = __builtin_return_address(0);
tfrom = NULL;
for(rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
{
tpnt = rpnt->dyn;
if( tpnt->loadaddr < from
&& ( tfrom == NULL
|| tfrom->loadaddr < tpnt->loadaddr))
{
tfrom = tpnt;
handle = rpnt->next;
}
}
}
ret = _dl_find_hash(name, handle, 1, NULL, 1);
/*
* Nothing found.
*/
if (!ret)
_dl_error_number = DL_NO_SYMBOL;
return ret;
}
int _dlclose(void * vhandle)
{
return do_dlclose(vhandle, 1);
}
static int do_dlclose(void * vhandle, int need_fini)
{
struct dyn_elf * rpnt, *rpnt1;
struct dyn_elf *spnt, *spnt1;
struct elf_phdr * ppnt;
struct elf_resolve * tpnt;
int (*dl_elf_fini)(void);
void (*dl_brk)(void);
struct dyn_elf * handle;
unsigned int end;
int i = 0;
handle = (struct dyn_elf *) vhandle;
rpnt1 = NULL;
for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
{
if(rpnt == handle) {
break;
}
rpnt1 = rpnt;
}
if (!rpnt) {
_dl_error_number = DL_BAD_HANDLE;
return 1;
}
/* OK, this is a valid handle - now close out the file.
* We check if we need to call fini () on the handle. */
spnt = need_fini ? handle : handle->next;
for(; spnt; spnt = spnt1)
{
spnt1 = spnt->next;
/* We appended the module list to the end - when we get back here,
quit. The access counts were not adjusted to account for being here. */
if (spnt == _dl_symbol_tables) break;
if(spnt->dyn->usage_count==1 && spnt->dyn->libtype == loaded_file) {
tpnt = spnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
if(tpnt->dynamic_info[DT_FINI]) {
dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_FINI]);
(*dl_elf_fini)();
}
}
}
if(rpnt1)
rpnt1->next_handle = rpnt->next_handle;
else
_dl_handles = rpnt->next_handle;
/* OK, this is a valid handle - now close out the file */
for(rpnt = handle; rpnt; rpnt = rpnt1)
{
rpnt1 = rpnt->next;
/* We appended the module list to the end - when we get back here,
quit. The access counts were not adjusted to account for being here. */
if (rpnt == _dl_symbol_tables) break;
rpnt->dyn->usage_count--;
if(rpnt->dyn->usage_count == 0 && rpnt->dyn->libtype == loaded_file)
{
tpnt = rpnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
#if 0
/* We have to do this above, before we start closing objects.
Otherwise when the needed symbols for _fini handling are
resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
if(tpnt->dynamic_info[DT_FINI]) {
dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_FINI]);
(*dl_elf_fini)();
}
#endif
end = 0;
for(i = 0, ppnt = rpnt->dyn->ppnt;
i < rpnt->dyn->n_phent; ppnt++, i++) {
if (ppnt->p_type != PT_LOAD) continue;
if (end < ppnt->p_vaddr + ppnt->p_memsz)
end = ppnt->p_vaddr + ppnt->p_memsz;
}
_dl_munmap (rpnt->dyn->loadaddr, end);
/* Next, remove rpnt->dyn from the loaded_module list */
if (_dl_loaded_modules == rpnt->dyn)
{
_dl_loaded_modules = rpnt->dyn->next;
if (_dl_loaded_modules)
_dl_loaded_modules->prev = 0;
}
else
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
if (tpnt->next == rpnt->dyn) {
tpnt->next = tpnt->next->next;
if (tpnt->next)
tpnt->next->prev = tpnt;
break;
}
free(rpnt->dyn->libname);
free(rpnt->dyn);
}
free(rpnt);
}
dl_brk = (void (*)()) _dl_debug_addr->r_brk;
if( dl_brk != NULL )
{
_dl_debug_addr->r_state = RT_DELETE;
(*dl_brk)();
_dl_debug_addr->r_state = RT_CONSISTENT;
(*dl_brk)();
}
return 0;
}
const char * _dlerror()
{
const char * retval;
if(!_dl_error_number) return NULL;
retval = dl_error_names[_dl_error_number];
_dl_error_number = 0;
return retval;
}
/* Generate the correct symbols that we need. */
#if 1
#pragma weak dlopen = _dlopen
#pragma weak dlerror = _dlerror
#pragma weak dlclose = _dlclose
#pragma weak dlsym = _dlsym
#pragma weak dladdr = _dladdr
#else
__asm__(".weak dlopen;dlopen=_dlopen");
__asm__(".weak dlerror;dlerror=_dlerror");
__asm__(".weak dlclose;dlclose=_dlclose");
__asm__(".weak dlsym;dlsym=_dlsym");
__asm__(".weak dladdr;dladdr=_dladdr");
#endif
/* This is a real hack. We need access to the dynamic linker, but we
also need to make it possible to link against this library without any
unresolved externals. We provide these weak symbols to make the link
possible, but at run time the normal symbols are accessed. */
static void foobar()
{
_dl_fdprintf(2,"libdl library not correctly linked\n");
_dl_exit(1);
}
static int foobar1 = (int)foobar; /* Use as pointer */
#if 1
#pragma weak _dl_find_hash = foobar
#pragma weak _dl_symbol_tables = foobar1
#pragma weak _dl_handles = foobar1
#pragma weak _dl_loaded_modules = foobar1
#pragma weak _dl_debug_addr = foobar1
#pragma weak _dl_error_number = foobar1
#pragma weak _dl_load_shared_library = foobar
#ifdef USE_CACHE
#pragma weak _dl_map_cache = foobar
#pragma weak _dl_unmap_cache = foobar
#endif
#pragma weak _dl_malloc_function = foobar1
#pragma weak _dl_parse_relocation_information = foobar
#pragma weak _dl_parse_lazy_relocation_information = foobar
#pragma weak _dl_fdprintf = foobar
#else
__asm__(".weak _dl_find_hash; _dl_find_hash = foobar");
__asm__(".weak _dl_symbol_tables; _dl_symbol_tables = foobar1");
__asm__(".weak _dl_handles; _dl_handles = foobar1");
__asm__(".weak _dl_loaded_modules; _dl_loaded_modules = foobar1");
__asm__(".weak _dl_debug_addr; _dl_debug_addr = foobar1");
__asm__(".weak _dl_error_number; _dl_error_number = foobar1");
__asm__(".weak _dl_load_shared_library; _dl_load_shared_library = foobar");
#ifdef USE_CACHE
__asm__(".weak _dl_map_cache; _dl_map_cache = foobar");
__asm__(".weak _dl_unmap_cache; _dl_unmap_cache = foobar");
#endif
__asm__(".weak _dl_malloc_function; _dl_malloc_function = foobar1");
__asm__(".weak _dl_parse_relocation_information; _dl_parse_relocation_information = foobar");
__asm__(".weak _dl_parse_lazy_relocation_information; _dl_parse_lazy_relocation_information = foobar");
__asm__(".weak _dl_fdprintf; _dl_fdprintf = foobar");
#endif
/*
* Dump information to stderrr about the current loaded modules
*/
static char * type[] = {"Lib","Exe","Int","Mod"};
void _dlinfo()
{
struct elf_resolve * tpnt;
struct dyn_elf * rpnt, *hpnt;
_dl_fdprintf(2, "List of loaded modules\n");
/* First start with a complete list of all of the loaded files. */
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
_dl_fdprintf(2, "\t%8.8x %8.8x %8.8x %s %d %s\n",
(unsigned)tpnt->loadaddr, (unsigned)tpnt,
(unsigned)tpnt->symbol_scope,
type[tpnt->libtype],
tpnt->usage_count,
tpnt->libname);
/* Next dump the module list for the application itself */
_dl_fdprintf(2, "\nModules for application (%x):\n",
(unsigned)_dl_symbol_tables);
for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
_dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
rpnt->dyn->libname);
for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle)
{
_dl_fdprintf(2, "Modules for handle %x\n", (unsigned)hpnt);
for(rpnt = hpnt; rpnt; rpnt = rpnt->next)
_dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
rpnt->dyn->libname);
}
}
int _dladdr(void * __address, Dl_info * __dlip )
{
struct elf_resolve * pelf;
struct elf_resolve * rpnt;
#ifdef USE_CACHE
_dl_map_cache();
#endif
/*
* Try and locate the module address is in
*/
pelf = NULL;
#if 0
_dl_fdprintf( 2,
"dladdr( 0x%p, 0x%p )\n",
__address, __dlip );
#endif
for(rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
{
struct elf_resolve * tpnt;
tpnt = rpnt;
#if 0
_dl_fdprintf( 2,
"Module \"%s\" at 0x%p\n",
tpnt->libname,
tpnt->loadaddr );
#endif
if( tpnt->loadaddr < (char*)__address
&& ( pelf == NULL
|| pelf->loadaddr < tpnt->loadaddr))
pelf = tpnt;
}
if ( ! pelf )
{
return 0;
}
/*
* Try and locate the symbol of address
*/
{
char * strtab;
struct elf32_sym * symtab;
int hn, si;
int sf;
int sn = 0;
void* sa = 0;
symtab = (struct elf32_sym *) (pelf->dynamic_info[DT_SYMTAB] +
pelf->loadaddr);
strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
sf = 0;
for(hn = 0; hn < pelf->nbucket; hn++)
{
for(si = pelf->elf_buckets[hn]; si; si = pelf->chains[si])
{
void* symbol_addr;
symbol_addr = pelf->loadaddr + symtab[si].st_value;
if ( symbol_addr <= __address &&
( !sf || sa < symbol_addr ) )
{
sa = symbol_addr;
sn = si;
sf = 1;
}
#if 0
_dl_fdprintf( 2,
"Symbol \"%s\" at 0x%p\n",
strtab + symtab[si].st_name,
symbol_addr );
#endif
}
}
if ( sf )
{
__dlip->dli_fname = pelf->libname;
__dlip->dli_fbase = pelf->loadaddr;
__dlip->dli_sname = strtab + symtab[sn].st_name;
__dlip->dli_saddr = sa;
}
return 1;
}
}

648
ldso/libdl/libdl.c Normal file
View File

@@ -0,0 +1,648 @@
/*
* libdl.c
*
* Functions required for dlopen et. al.
*/
#include "dlfcn.h"
/* #include "link.h" */
#include <stdlib.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "sysdep.h"
#include "syscall.h"
#include "hash.h"
#include "string.h"
#include "linuxelf.h"
extern int _dl_error_number;
extern struct r_debug * _dl_debug_addr;
extern void * (*_dl_malloc_function)(size_t size);
static int do_fixup(struct elf_resolve * tpnt, int flag);
static int do_dlclose(void *, int need_fini);
void * _dlopen(char * filename, int flag);
const char * _dlerror(void);
void * _dlsym(void *, char *);
int _dlclose(void *);
int _dladdr(void * __address, Dl_info * __dlip );
static const char * dl_error_names[] = {
"",
"File not found",
"Unable to open /dev/zero",
"Not an ELF file",
#if defined (__i386__)
"Not i386 binary",
#elif defined (__sparc__)
"Not sparc binary",
#elif defined (__mc68000__)
"Not m68k binary",
#else
"Unrecognized binary type",
#endif
"Not an ELF shared library",
"Unable to mmap file",
"No dynamic section",
#ifdef ELF_USES_RELOCA
"Unable to process REL relocs",
#else
"Unable to process RELA relocs",
#endif
"Bad handle",
"Unable to resolve symbol"
};
static void dl_cleanup(void) __attribute__ ((destructor));
static void dl_cleanup(void)
{
struct dyn_elf* d;
for (d = _dl_handles; d; d = d->next_handle)
if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI])
{
(*((int(*)(void))(d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI])))();
d->dyn->dynamic_info[DT_FINI] = 0;
}
}
void * _dlopen(char * libname, int flag)
{
struct elf_resolve * tpnt, *tfrom;
struct dyn_elf * rpnt;
struct dyn_elf * dyn_chain;
struct dyn_elf * dpnt;
static int dl_init = 0;
char * from;
void (*dl_brk)(void);
int (*dl_elf_init)(void);
from = __builtin_return_address(0);
/* Have the dynamic linker use the regular malloc function now */
if (!dl_init) {
dl_init++;
_dl_malloc_function = malloc;
}
/* Cover the trivial case first */
if (!libname) return _dl_symbol_tables;
#ifdef USE_CACHE
_dl_map_cache();
#endif
/*
* Try and locate the module we were called from - we
* need this so that we get the correct RPATH. Note that
* this is the current behavior under Solaris, but the
* ABI+ specifies that we should only use the RPATH from
* the application. Thus this may go away at some time
* in the future.
*/
tfrom = NULL;
for(dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next)
{
tpnt = dpnt->dyn;
if( tpnt->loadaddr < from
&& ( tfrom == NULL
|| tfrom->loadaddr < tpnt->loadaddr))
tfrom = tpnt;
}
if(!(tpnt = _dl_load_shared_library(0, tfrom, libname)))
{
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
return NULL;
}
tpnt->usage_count++;
dyn_chain = rpnt =
(struct dyn_elf *) malloc(sizeof(struct dyn_elf));
_dl_memset (rpnt, 0, sizeof(*rpnt));
rpnt->dyn = tpnt;
rpnt->flags = flag;
if (!tpnt->symbol_scope) tpnt->symbol_scope = dyn_chain;
rpnt->next_handle = _dl_handles;
_dl_handles = rpnt;
/*
* OK, we have the requested file in memory. Now check for
* any other requested files that may also be required.
*/
{
struct elf_resolve *tcurr;
struct elf_resolve * tpnt1;
struct dynamic * dpnt;
char * lpnt;
tcurr = tpnt;
do{
for(dpnt = (struct dynamic *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
{
if(dpnt->d_tag == DT_NEEDED)
{
lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
dpnt->d_un.d_val;
if(!(tpnt1 = _dl_load_shared_library(0, tcurr, lpnt)))
goto oops;
rpnt->next =
(struct dyn_elf *) malloc(sizeof(struct dyn_elf));
_dl_memset (rpnt->next, 0, sizeof (*(rpnt->next)));
rpnt = rpnt->next;
tpnt1->usage_count++;
if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
rpnt->dyn = tpnt1;
};
}
tcurr = tcurr->next;
} while(tcurr);
}
/*
* OK, now attach the entire chain at the end
*/
rpnt->next = _dl_symbol_tables;
if (do_fixup(tpnt, flag)) {
_dl_error_number = DL_NO_SYMBOL;
goto oops;
}
dl_brk = (void (*)()) _dl_debug_addr->r_brk;
if( dl_brk != NULL )
{
_dl_debug_addr->r_state = RT_ADD;
(*dl_brk)();
_dl_debug_addr->r_state = RT_CONSISTENT;
(*dl_brk)();
}
for(rpnt = dyn_chain; rpnt; rpnt = rpnt->next)
{
tpnt = rpnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
if (tpnt->libtype == elf_executable) continue;
if (tpnt->init_flag & INIT_FUNCS_CALLED) continue;
tpnt->init_flag |= INIT_FUNCS_CALLED;
if(tpnt->dynamic_info[DT_INIT]) {
dl_elf_init = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_INIT]);
(*dl_elf_init)();
}
}
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
return (void *) dyn_chain;
oops:
/* Something went wrong. Clean up and return NULL. */
#ifdef USE_CACHE
_dl_unmap_cache();
#endif
do_dlclose (dyn_chain, 0);
return NULL;
}
static int do_fixup(struct elf_resolve * tpnt, int flag)
{
int goof = 0;
if(tpnt->next) goof += do_fixup(tpnt->next, flag);
if(tpnt->dynamic_info[DT_REL]) {
#ifdef ELF_USES_RELOCA
goof++;
#else
if (tpnt->init_flag & RELOCS_DONE) return goof;
tpnt->init_flag |= RELOCS_DONE;
goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
tpnt->dynamic_info[DT_RELSZ], 0);
#endif
}
if(tpnt->dynamic_info[DT_RELA]) {
#ifdef ELF_USES_RELOCA
if (tpnt->init_flag & RELOCS_DONE) return goof;
tpnt->init_flag |= RELOCS_DONE;
goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
tpnt->dynamic_info[DT_RELASZ], 0);
#else
goof++;
#endif
}
if(tpnt->dynamic_info[DT_JMPREL])
{
if (tpnt->init_flag & JMP_RELOCS_DONE) return goof;
tpnt->init_flag |= JMP_RELOCS_DONE;
if(flag == RTLD_LAZY)
_dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info[DT_PLTRELSZ], 0);
else
goof += _dl_parse_relocation_information(tpnt,
tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info[DT_PLTRELSZ], 0);
};
return goof;
}
void * _dlsym(void * vhandle, char * name)
{
struct elf_resolve * tpnt, *tfrom;
struct dyn_elf * handle;
char * from;
struct dyn_elf * rpnt;
void *ret;
handle = (struct dyn_elf *) vhandle;
/* First of all verify that we have a real handle
of some kind. Return NULL if not a valid handle. */
if (handle == NULL)
handle = _dl_symbol_tables;
else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
if (rpnt == handle) break;
if (!rpnt) {
_dl_error_number = DL_BAD_HANDLE;
return NULL;
}
}
else if (handle == RTLD_NEXT )
{
/*
* Try and locate the module we were called from - we
* need this so that we know where to start searching
* from. We never pass RTLD_NEXT down into the actual
* dynamic loader itself, as it doesn't know
* how to properly treat it.
*/
from = __builtin_return_address(0);
tfrom = NULL;
for(rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
{
tpnt = rpnt->dyn;
if( tpnt->loadaddr < from
&& ( tfrom == NULL
|| tfrom->loadaddr < tpnt->loadaddr))
{
tfrom = tpnt;
handle = rpnt->next;
}
}
}
ret = _dl_find_hash(name, handle, 1, NULL, 1);
/*
* Nothing found.
*/
if (!ret)
_dl_error_number = DL_NO_SYMBOL;
return ret;
}
int _dlclose(void * vhandle)
{
return do_dlclose(vhandle, 1);
}
static int do_dlclose(void * vhandle, int need_fini)
{
struct dyn_elf * rpnt, *rpnt1;
struct dyn_elf *spnt, *spnt1;
struct elf_phdr * ppnt;
struct elf_resolve * tpnt;
int (*dl_elf_fini)(void);
void (*dl_brk)(void);
struct dyn_elf * handle;
unsigned int end;
int i = 0;
handle = (struct dyn_elf *) vhandle;
rpnt1 = NULL;
for(rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
{
if(rpnt == handle) {
break;
}
rpnt1 = rpnt;
}
if (!rpnt) {
_dl_error_number = DL_BAD_HANDLE;
return 1;
}
/* OK, this is a valid handle - now close out the file.
* We check if we need to call fini () on the handle. */
spnt = need_fini ? handle : handle->next;
for(; spnt; spnt = spnt1)
{
spnt1 = spnt->next;
/* We appended the module list to the end - when we get back here,
quit. The access counts were not adjusted to account for being here. */
if (spnt == _dl_symbol_tables) break;
if(spnt->dyn->usage_count==1 && spnt->dyn->libtype == loaded_file) {
tpnt = spnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
if(tpnt->dynamic_info[DT_FINI]) {
dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_FINI]);
(*dl_elf_fini)();
}
}
}
if(rpnt1)
rpnt1->next_handle = rpnt->next_handle;
else
_dl_handles = rpnt->next_handle;
/* OK, this is a valid handle - now close out the file */
for(rpnt = handle; rpnt; rpnt = rpnt1)
{
rpnt1 = rpnt->next;
/* We appended the module list to the end - when we get back here,
quit. The access counts were not adjusted to account for being here. */
if (rpnt == _dl_symbol_tables) break;
rpnt->dyn->usage_count--;
if(rpnt->dyn->usage_count == 0 && rpnt->dyn->libtype == loaded_file)
{
tpnt = rpnt->dyn;
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
#if 0
/* We have to do this above, before we start closing objects.
Otherwise when the needed symbols for _fini handling are
resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/
if(tpnt->dynamic_info[DT_FINI]) {
dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
tpnt->dynamic_info[DT_FINI]);
(*dl_elf_fini)();
}
#endif
end = 0;
for(i = 0, ppnt = rpnt->dyn->ppnt;
i < rpnt->dyn->n_phent; ppnt++, i++) {
if (ppnt->p_type != PT_LOAD) continue;
if (end < ppnt->p_vaddr + ppnt->p_memsz)
end = ppnt->p_vaddr + ppnt->p_memsz;
}
_dl_munmap (rpnt->dyn->loadaddr, end);
/* Next, remove rpnt->dyn from the loaded_module list */
if (_dl_loaded_modules == rpnt->dyn)
{
_dl_loaded_modules = rpnt->dyn->next;
if (_dl_loaded_modules)
_dl_loaded_modules->prev = 0;
}
else
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
if (tpnt->next == rpnt->dyn) {
tpnt->next = tpnt->next->next;
if (tpnt->next)
tpnt->next->prev = tpnt;
break;
}
free(rpnt->dyn->libname);
free(rpnt->dyn);
}
free(rpnt);
}
dl_brk = (void (*)()) _dl_debug_addr->r_brk;
if( dl_brk != NULL )
{
_dl_debug_addr->r_state = RT_DELETE;
(*dl_brk)();
_dl_debug_addr->r_state = RT_CONSISTENT;
(*dl_brk)();
}
return 0;
}
const char * _dlerror()
{
const char * retval;
if(!_dl_error_number) return NULL;
retval = dl_error_names[_dl_error_number];
_dl_error_number = 0;
return retval;
}
/* Generate the correct symbols that we need. */
#if 1
#pragma weak dlopen = _dlopen
#pragma weak dlerror = _dlerror
#pragma weak dlclose = _dlclose
#pragma weak dlsym = _dlsym
#pragma weak dladdr = _dladdr
#else
__asm__(".weak dlopen;dlopen=_dlopen");
__asm__(".weak dlerror;dlerror=_dlerror");
__asm__(".weak dlclose;dlclose=_dlclose");
__asm__(".weak dlsym;dlsym=_dlsym");
__asm__(".weak dladdr;dladdr=_dladdr");
#endif
/* This is a real hack. We need access to the dynamic linker, but we
also need to make it possible to link against this library without any
unresolved externals. We provide these weak symbols to make the link
possible, but at run time the normal symbols are accessed. */
static void foobar()
{
_dl_fdprintf(2,"libdl library not correctly linked\n");
_dl_exit(1);
}
static int foobar1 = (int)foobar; /* Use as pointer */
#if 1
#pragma weak _dl_find_hash = foobar
#pragma weak _dl_symbol_tables = foobar1
#pragma weak _dl_handles = foobar1
#pragma weak _dl_loaded_modules = foobar1
#pragma weak _dl_debug_addr = foobar1
#pragma weak _dl_error_number = foobar1
#pragma weak _dl_load_shared_library = foobar
#ifdef USE_CACHE
#pragma weak _dl_map_cache = foobar
#pragma weak _dl_unmap_cache = foobar
#endif
#pragma weak _dl_malloc_function = foobar1
#pragma weak _dl_parse_relocation_information = foobar
#pragma weak _dl_parse_lazy_relocation_information = foobar
#pragma weak _dl_fdprintf = foobar
#else
__asm__(".weak _dl_find_hash; _dl_find_hash = foobar");
__asm__(".weak _dl_symbol_tables; _dl_symbol_tables = foobar1");
__asm__(".weak _dl_handles; _dl_handles = foobar1");
__asm__(".weak _dl_loaded_modules; _dl_loaded_modules = foobar1");
__asm__(".weak _dl_debug_addr; _dl_debug_addr = foobar1");
__asm__(".weak _dl_error_number; _dl_error_number = foobar1");
__asm__(".weak _dl_load_shared_library; _dl_load_shared_library = foobar");
#ifdef USE_CACHE
__asm__(".weak _dl_map_cache; _dl_map_cache = foobar");
__asm__(".weak _dl_unmap_cache; _dl_unmap_cache = foobar");
#endif
__asm__(".weak _dl_malloc_function; _dl_malloc_function = foobar1");
__asm__(".weak _dl_parse_relocation_information; _dl_parse_relocation_information = foobar");
__asm__(".weak _dl_parse_lazy_relocation_information; _dl_parse_lazy_relocation_information = foobar");
__asm__(".weak _dl_fdprintf; _dl_fdprintf = foobar");
#endif
/*
* Dump information to stderrr about the current loaded modules
*/
static char * type[] = {"Lib","Exe","Int","Mod"};
void _dlinfo()
{
struct elf_resolve * tpnt;
struct dyn_elf * rpnt, *hpnt;
_dl_fdprintf(2, "List of loaded modules\n");
/* First start with a complete list of all of the loaded files. */
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
_dl_fdprintf(2, "\t%8.8x %8.8x %8.8x %s %d %s\n",
(unsigned)tpnt->loadaddr, (unsigned)tpnt,
(unsigned)tpnt->symbol_scope,
type[tpnt->libtype],
tpnt->usage_count,
tpnt->libname);
/* Next dump the module list for the application itself */
_dl_fdprintf(2, "\nModules for application (%x):\n",
(unsigned)_dl_symbol_tables);
for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
_dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
rpnt->dyn->libname);
for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle)
{
_dl_fdprintf(2, "Modules for handle %x\n", (unsigned)hpnt);
for(rpnt = hpnt; rpnt; rpnt = rpnt->next)
_dl_fdprintf(2, "\t%8.8x %s\n", (unsigned)rpnt->dyn,
rpnt->dyn->libname);
}
}
int _dladdr(void * __address, Dl_info * __dlip )
{
struct elf_resolve * pelf;
struct elf_resolve * rpnt;
#ifdef USE_CACHE
_dl_map_cache();
#endif
/*
* Try and locate the module address is in
*/
pelf = NULL;
#if 0
_dl_fdprintf( 2,
"dladdr( 0x%p, 0x%p )\n",
__address, __dlip );
#endif
for(rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
{
struct elf_resolve * tpnt;
tpnt = rpnt;
#if 0
_dl_fdprintf( 2,
"Module \"%s\" at 0x%p\n",
tpnt->libname,
tpnt->loadaddr );
#endif
if( tpnt->loadaddr < (char*)__address
&& ( pelf == NULL
|| pelf->loadaddr < tpnt->loadaddr))
pelf = tpnt;
}
if ( ! pelf )
{
return 0;
}
/*
* Try and locate the symbol of address
*/
{
char * strtab;
struct elf32_sym * symtab;
int hn, si;
int sf;
int sn = 0;
void* sa = 0;
symtab = (struct elf32_sym *) (pelf->dynamic_info[DT_SYMTAB] +
pelf->loadaddr);
strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
sf = 0;
for(hn = 0; hn < pelf->nbucket; hn++)
{
for(si = pelf->elf_buckets[hn]; si; si = pelf->chains[si])
{
void* symbol_addr;
symbol_addr = pelf->loadaddr + symtab[si].st_value;
if ( symbol_addr <= __address &&
( !sf || sa < symbol_addr ) )
{
sa = symbol_addr;
sn = si;
sf = 1;
}
#if 0
_dl_fdprintf( 2,
"Symbol \"%s\" at 0x%p\n",
strtab + symtab[si].st_name,
symbol_addr );
#endif
}
}
if ( sf )
{
__dlip->dli_fname = pelf->libname;
__dlip->dli_fbase = pelf->loadaddr;
__dlip->dli_sname = strtab + symtab[sn].st_name;
__dlip->dli_saddr = sa;
}
return 1;
}
}

11
ldso/man/Makefile Normal file
View File

@@ -0,0 +1,11 @@
include ../Config.mk
ALL = #ld.so.info
all: $(ALL)
ld.so.info: ld.so.texi
makeinfo $<
clean:
rm -f $(ALL) *~

218
ldso/man/dlopen.3 Normal file
View File

@@ -0,0 +1,218 @@
.\" -*- nroff -*-
.\" Copyright 1995 Yggdrasil Computing, Incorporated.
.\" written by Adam J. Richter (adam@yggdrasil.com),
.\" with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com).
.\"
.\" This is free documentation; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public License as
.\" published by the Free Software Foundation; either version 2 of
.\" the License, or (at your option) any later version.
.\"
.\" The GNU General Public License's references to "object code"
.\" and "executables" are to be interpreted as the output of any
.\" document formatting or typesetting system, including
.\" intermediate and printed output.
.\"
.\" This manual is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public
.\" License along with this manual; if not, write to the Free
.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
.\" USA.
.\"
.TH DLOPEN 3 "16 May 1995" "Linux" "Linux Programmer's Manual"
.SH NAME
dlclose, dlerror, dlopen, dlsym \- Programming interface to dynamic linking loader.
.SH SYNOPSIS
.B #include <dlfcn.h>
.sp
.BI "void *dlopen (const char *" "filename" ", int " flag ");
.br
.BI "const char *dlerror(void);"
.br
.BI "void *dlsym(void *"handle ", char *"symbol ");"
.br
.BI "int dladdr(void *"address ", Dl_info *"dlip ");"
.br
.BI "int dlclose (void *"handle ");
.sp
Special symbols:
.BR "_init" ", " "_fini" ". "
.SH DESCRIPTION
.B dlopen
loads a dynamic library from the file named by the null terminated
string
.I filename
and returns an opaque "handle" for the dynamic library.
If
.I filename
is not an absolute path (i.e., it does not begin with a "/"), then the
file is searched for in the following locations:
.RS
.PP
A colon-separated list of directories in the user's
\fBLD_LIBRARY\fP path environment variable.
.PP
The list of libraries specified in \fI/etc/ld.so.cache\fP.
.PP
\fI/usr/lib\fP, followed by \fI/lib\fP.
.RE
.PP
If
.I filename
is a NULL pointer, then the returned handle is for the main program.
.PP
External references in the library are resolved using the libraries
in that library's dependency list and any other libraries previously
opened with the
.B RTLD_GLOBAL
flag.
If the executable was linked
with the flag "-rdynamic", then the global symbols in the executable
will also be used to resolve references in a dynamically loaded
library.
.PP
.I flag
must be either
.BR RTLD_LAZY ,
meaning resolve undefined symbols as code from the dynamic library is
executed, or
.BR RTLD_NOW ,
meaning resolve all undefined symbols before
.B dlopen
returns, and fail if this cannot be done.
Optionally,
.B RTLD_GLOBAL
may be or'ed with
.IR flag,
in which case the external symbols defined in the library will be
made available to subsequently loaded libraries.
.PP
If the library exports a routine named
.BR _init ,
then that code is executed before dlopen returns.
If the same library is loaded twice with
.BR dlopen() ,
the same file handle is returned. The dl library maintains link
counts for dynamic file handles, so a dynamic library is not
deallocated until
.B dlclose
has been called on it as many times as
.B dlopen
has succeeded on it.
.PP
If
.B dlopen
fails for any reason, it returns NULL.
A human readable string describing the most recent error that occurred
from any of the dl routines (dlopen, dlsym or dlclose) can be
extracted with
.BR dlerror() .
.B dlerror
returns NULL if no errors have occurred since initialization or since
it was last called. (Calling
.B dlerror()
twice consecutively, will always result in the second call returning
NULL.)
.B dlsym
takes a "handle" of a dynamic library returned by dlopen and the null
terminated symbol name, returning the address where that symbol is
loaded. If the symbol is not found,
.B dlsym
returns NULL; however, the correct way to test for an error from
.B dlsym
is to save the result of
.B dlerror
into a variable, and then check if saved value is not NULL.
This is because the value of the symbol could actually be NULL.
It is also necessary to save the results of
.B dlerror
into a variable because if
.B dlerror
is called again, it will return NULL.
.PP
.B dladdr
returns information about the shared library containing the memory
location specified by
.IR address .
.B dladdr
returns zero on success and non-zero on error.
.PP
.B dlclose
decrements the reference count on the dynamic library handle
.IR handle .
If the reference count drops to zero and no other loaded libraries use
symbols in it, then the dynamic library is unloaded. If the dynamic
library exports a routine named
.BR _fini ,
then that routine is called just before the library is unloaded.
.SH EXAMPLES
.B Load the math library, and print the cosine of 2.0:
.RS
.nf
.if t .ft CW
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle = dlopen ("/lib/libm.so", RTLD_LAZY);
double (*cosine)(double) = dlsym(handle, "cos");
printf ("%f\\n", (*cosine)(2.0));
dlclose(handle);
}
.if t .ft P
.fi
.PP
If this program were in a file named "foo.c", you would build the program
with the following command:
.RS
.LP
gcc -rdynamic -o foo foo.c -ldl
.RE
.RE
.LP
.B Do the same thing, but check for errors at every step:
.RS
.nf
.if t .ft CW
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("/lib/libm.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
printf ("%f\\n", (*cosine)(2.0));
dlclose(handle);
}
.if t .ft P
.fi
.RE
.SH ACKNOWLEDGEMENTS
The dlopen interface standard comes from Solaris.
The Linux dlopen implementation was primarily written by
Eric Youngdale with help from Mitch D'Souza, David Engel,
Hongjiu Lu, Andreas Schwab and others.
The manual page was written by Adam Richter.
.SH SEE ALSO
.BR ld(1) ,
.BR ld.so(8) ,
.BR ldconfig(8) ,
.BR ldd(1) ,
.BR ld.so.info .

113
ldso/man/ld.so.8 Normal file
View File

@@ -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).

411
ldso/man/ld.so.texi Normal file
View File

@@ -0,0 +1,411 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename ld.so.info
@settitle ld.so : Dynamic-Link Library support
@c %**end of header
@ifinfo
This file documents the dynamic-link support libraries and utilities for the
Linux OS, version 1.8.1.
Copyright 1996 Michael Deutschmann
This document is subject to the GNU General Public License as published by
the Free Software foundation, version 2 or later (your choice).
Note: The software described in this document is under a different copyright
and license.
@end ifinfo
@titlepage
@title ld.so
@subtitle Dynamic Link library support for the Linux OS.
@author David Engel
@author Eric Youngdale
@author Peter Macdonald
@author Hongjiu Lu
@author Mitch D'Souza
@author Michael Deutschmann (this documentation)
@page
Copyright @copyright{} 1996 Michael Deutschmann
This document is subject to the GNU General Public License as published by
the Free Software foundation, version 2 or later (your choice).
Note: The software described in this document is under a different copyright
and license.
@end titlepage
@ifinfo
@node Top
@top
The @code{ld.so} module provides dynamic linked library support in Linux.
This file documents @code{ld.so} and its companion software.
@menu
* intro:: Introduction
* ld.so:: The dynamic linker core program
* ldd:: A utility to print out dependencies
* ldconfig:: A utility to maintain the cache and symlinks
* libdl:: Manual dynamic linking library
@end menu
@end ifinfo
@node intro
@unnumbered Introduction
The @code{ld.so} suite contains special files and utilities needed for linux
to handle @dfn{dynamic libraries}.
Ordinary static libraries (@file{lib*.a} files) are included into executables
that use their functions. A file that only uses static libraries needs less
intelligence to load, but takes up more space. If many executables use the
same library, there can be much wastage of storage space, since multiple
copies of the library functions are scattered across the executables.
However, static libraries are easier to make.
Dynamic libraries (@file{lib*.so*} files) are not copied into executables ---
the executable is written in such a way that it will automatically load the
libraries. In linux, the executable will first load the special library
@code{ld.so} or @code{ld-linux.so}, which contains the intelligence
to load further dynamic libraries. Since multiple files end up getting
executable data from the same file, dynamic libraries are also known as
shared libraries.
Linux executables come in two flavors, @sc{elf} and a.out.
a.out is the original executable format used by Linux. It has somewhat less
overhead than @sc{elf}. However creating shared libraries for a.out is
@emph{very} involved, and each a.out shared library must be explicitly
registered.
@sc{elf} is a more recent format, which supports a much simpler method of
creating libraries. @sc{elf} libraries may also be linked manually
(@pxref{libdl}).
Since many library authors prefer @sc{elf} and no longer release shared a.out
libraries, a.out is moribund on Linux. This version of the @code{ld.so} can
be compiled to support only @sc{elf}, or to support both formats. (The last
release of ld.so to support a.out alone was 1.8.0.)
@node ld.so
@chapter @code{ld.so}: Dynamic linker core
@code{ld.so} works behind the scenes to handle dynamic libraries in Linux.
Users will almost never have to deal with it directly, but in special cases
one can send instructions to it through environment variables. Also, if
something is wrong with your libraries (usually an incorrect version) ld.so
will give error messages.
Actually @code{ld.so} is the a.out linker. The new @sc{elf} executables are
handled by a related program @code{ld-linux.so}.
@menu
* files:: Configuration files used by the suite
* environment:: Environment settings that tweak @code{ld.so}
* errors:: Complaints @code{ld.so} might make
@end menu
@node files
@section Configuration Files
@table @file
@item /etc/ld.so.cache
A file created by @code{ldconfig} and used to speed linking. It's structure
is private to the suite.
@item /etc/ld.so.conf
A simple list of directories to scan for libraries, in addition to
@file{/usr/lib} and @file{/lib}, which are hardwired. It may contain
comments started with a @samp{#}.
@item /etc/ld.so.preload
A list of libraries to preload. This allows preloading libraries for
setuid/setgid executables securely. It may contain comments.
@end table
@node environment
@section Environment Variables
@table @code
@item LD_AOUT_LIBRARY_PATH
@itemx LD_LIBRARY_PATH
These variables supply a library path for finding dynamic libraries, in the
standard colon seperated format. These variables are ignored when executing
setuid/setgid programs, because otherwise they would be a security hazard.
@code{ld.so} will use @code{LD_AOUT_LIBRARY_PATH} and @code{ld-linux.so} will
use @code{LD_LIBRARY_PATH}.
@item LD_AOUT_PRELOAD
@itemx LD_PRELOAD
These variables allow an extra library not specified in the executable to be
loaded. Generally this is only useful if you want to override a function.
These are also ignored when running setuid/setgid executables. @code{ld.so}
will use @code{LD_AOUT_PRELOAD} and @code{ld-linux.so} will use
@code{LD_PRELOAD}.
@item LD_NOWARN
If non-empty, errors about incompatible minor revisions are suppressed.
@item LD_KEEPDIR
If non-empty, allow executables to specify absolute library names. This
option is deprecated.
@c FIXME:
@c The following are things I noticed in the ld-linux.so source.
@c I don't really understand 'em. Could someone help me?
@c
@c @item LD_BIND_NOW
@c This option is used by the @code{ld-linux.so} only. I don't know
@c what it does. (I suspect, looking at the code, that it specifies
@c "RTLD_NOW" rather than "RTLD_LAZY" mode for the shared libraries.)
@c
@c @item LD_TRACE_LOADED_OBJECTS
@c @itemx LD_WARN
@c These seem to have something to do with the communication between the
@c @code{ld-linux.so} and @code{ldd}. I don't know more.
@end table
@node errors
@section Errors
@table @samp
@item Can't find library @var{library}
The executable required a dynamically linked library that ld.so cannot find.
Your symbolic links may be not set right, or you may have not installed a
library needed by the program.
@item Can't load library @var{library}
The library is corrupt.
@item Incompatible library @var{library}
@itemx Require major version @var{x} and found @var{y}
Your version of the library is incompatible with the executable. Recompiling
the executable, or upgrading the library will fix the problem.
@item using incompatible library @var{library}
@itemx Desire minor version >= @var{x} and found @var{y}.
Your version of the library is older than that expected by the executable,
but not so old that the library interface has radically changed, so the
linker will attempt to run anyway. There is a chance that it will work, but
you should upgrade the library or recompile the software. The environment
variable @code{LD_NOWARN} can be used to supress this message.
@item too many directories in library path
The linker only supports up to 32 library directories. You have too many.
@item dynamic linker error in @var{blah}
The linker is having trouble handling a binary - it is probably corrupt.
@item can't map cache file @var{cache-file}
@itemx cache file @var{cache-file} @var{blah}
The linker cache file (generally @file{/etc/ld.so.cache}) is corrupt or
non-existent. These errors can be ignored, and can be prevented by
regenerating the cache file with @code{ldconfig}.
@end table
@node ldd
@chapter @code{ldd}: Dependency scanner
@code{ldd} is a utility that prints out the dynamic libraries that an
executable is linked to.
Actually @code{ldd} works by signalling ld.so to print the dependencies.
For a.out executables this is done by starting the executable with
@code{argc} equal to 0. The linker detects this and prints the dependencies.
(This can cause problems with @emph{very} old binaries, which would run as
normal only with an inappropriate @code{argc}.)
For @sc{elf} executables, special environment variables are used to tell the
linker to print the dependencies.
@code{ldd} has a few options:
@table @samp
@item -v
Print the version number of @code{ldd} itself
@item -V
Print the version number of the dynamic linker
@item -d
Report missing functions. This is only supported for @sc{elf} executables.
@item -r
Report missing objects. This is also only available for @sc{elf}
executables.
@end table
@node ldconfig
@chapter @code{ldconfig}: Setup program
This utility is used by the system administrator to automatically set up
symbolic links needed by the libraries, and also to set up the cache file.
@code{ldconfig} is run after new dynamic libraries are installed, and if the
cache file or links are damaged. It is also run when upgrading the
@code{ld.so} suite itself.
The @file{/lib} and @file{/usr/lib} directories, and any listed in the file
@file{/etc/ld.so.conf} are scanned by default unless @samp{-n} is used.
Additional directories may be specified on the command line.
It has the following options:
@table @samp
@item -D
Enter debug mode. Implies @samp{-N} and @samp{-X}.
@item -v
Verbose. Print out links created and directories scanned.
@item -n
Check directories specified on the commandline @emph{only}.
@item -N
Do not regenerate the cache.
@item -X
Do not rebuild symbolic links.
@item -l
Set up symbolic links for only libraries presented on the command line.
@item -p
Print out the library pathnames in the cache file (@file{/etc/ld.so.cache})
@end table
@node libdl
@chapter User dynamic linking library
The @code{ld.so} package includes a small library of functions
(@code{libdl}) to allow manual dynamic linking. Normally programs are linked
so that dynamic functions and objects are automagically available. These
functions allow one to manually load and access a symbol from a library.
They are only available for @sc{elf} executables.
@menu
* using libdl:: General points
* functions:: How to use the functions
* example:: A sample program
@end menu
@node using libdl
@section Overview
To access this library, add the flag @samp{-ldl} to your compile command when
linking the executable. You also must include the header file
@code{dlfcn.h}. You may also need the flag @samp{-rdynamic}, which enables
resolving references in the loaded libraries against your executable.
Generally, you will first use @code{dlopen} to open a library. Then you use
@code{dlsym} one or more times to access symbols. Finally you use
@code{dlclose} to close the library.
These facilities are most useful for language interpreters that provide
access to external libraries. Without @code{libdl}, it would be neccessary
to link the interpreter executable with any and all external libraries
needed by the programs it runs. With @code{libdl}, the interpreter only
needs to be linked with the libraries it uses itself, and can dynamically
load in additional ones if programs need it.
@node functions
@section Functions
@deftypefun void *dlopen ( const char @var{filename}, int @var{flags} )
This function opens the dynamic library specified by @var{filename}
and returns an abstract handle, which can be used in subsequent calls to
@code{dlsym}. The function will respect the @code{LD_ELF_LIBRARY_PATH} and
@code{LD_LIBRARY_PATH} environment variables.
@end deftypefun
The following flags can be used with @code{dlopen}:
@deftypevr Macro int RTLD_LAZY
Resolve symbols in the library as they are needed.
@end deftypevr
@deftypevr Macro int RTLD_NOW
Resolve all symbols in the library before returning, and fail if not all can
be resolved. This is mutually exclusive with @code{RTLD_LAZY}.
@end deftypevr
@deftypevr Macro int RTLD_GLOBAL
Make symbols in this library available for resolving symbols in other
libraries loaded with @code{dlopen}.
@end deftypevr
@deftypefun int dlclose ( void *@var{handle} )
This function releases a library handle.
Note that if a library opened twice, the handle will be the same. However,
a reference count is used, so you should still close the library as many
times as you open it.
@end deftypefun
@deftypefun void *dlsym (void *@var{handle},char *@var{symbol-name})
This function looks up the name @var{symbol-name} in the library and returns
it in the void pointer.
If there is an error, a null pointer will be returned. However, it is
possible for a valid name in the library to have a null value, so
@code{dlerror} should be used to check if there was an error.
@end deftypefun
@deftypefun {libdl function} {const char} *dlerror( void )
This function is used to read the error state. It returns a human-readable
string describing the last error, or null, meaning no error.
The function resets the error value each time it is called, so the result
should be copied into a variable. If the function is called more than once
after an error, the second and subsequent calls will return null.
@end deftypefun
@node example
@section Example program
Here is an example program that prints the cosine of two by manually linking
to the math library:
@example
@c The following was snarfed verbatim from the dlopen.3 man file.
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) @{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("/lib/libm.so", RTLD_LAZY);
if (!handle) @{
fputs (dlerror(), stderr);
exit(1);
@}
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) @{
fputs(error, stderr);
exit(1);
@}
printf ("%f\\n", (*cosine)(2.0));
dlclose(handle);
@}
@end example
@contents
@bye

189
ldso/man/ldconfig.8 Normal file
View File

@@ -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.

59
ldso/man/ldd.1 Normal file
View File

@@ -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).

38
ldso/util/Makefile Normal file
View File

@@ -0,0 +1,38 @@
TOPDIR=../../
include $(TOPDIR)Rules.mak
include ../Config.mk
CFLAGS += -DLDSO_ADDR="0x62f00020" # needed by ldd.o
CFLAGS += -I./ -I../../include/
LDFLAGS += -nostdlib ../../libc.a ../../crt0.o $(GCCINCDIR)/../libgcc.a
ALL = ldconfig ldd # lddstub
all: $(ALL)
CSRC= readelf.c ldconfig.c ldd.c
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
$(COBJS): %.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
readelf.o: readelf.c readelf2.c
ldconfig: ldconfig.o readelf.o
$(CC) -static $(CFLAGS) $^ $(LDFLAGS) -o $@
ldd: ldd.o readelf.o
$(CC) -static $(CFLAGS) $^ $(LDFLAGS) -o $@
#ifeq ($(DEBUG),true)
#STUBFLAGS = -Wl,-dynamic-linker,../d-link/ld-linux.so
#endif
#lddstub: lddstub.o
# $(CC) $(CFLAGS) $(LDFLAGS) $(STUBFLAGS) $^ -o $@
clean:
rm -f $(ALL) *.o *~ core

837
ldso/util/ldconfig.c Normal file
View File

@@ -0,0 +1,837 @@
/*
* ldconfig - update shared library symlinks
*
* usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...
* ldconfig -l [-Dv] lib ...
* ldconfig -p
* -D: debug mode, don't update links
* -v: verbose mode, print things as we go
* -q: quiet mode, don't print warnings
* -n: don't process standard directories
* -N: don't update the library cache
* -X: don't update the library links
* -l: library mode, manually link libraries
* -p: print the current library cache
* -f conf: use conf instead of /etc/ld.so.conf
* -C cache: use cache instead of /etc/ld.so.cache
* -r root: first, do a chroot to the indicated directory
* dir ...: directories to process
* lib ...: libraries to link
*
* Copyright 1994-2000 David Engel and Mitch D'Souza
*
* This program may be used for any purpose as long as this
* copyright notice is kept.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#include <dirent.h>
#include <unistd.h>
#include <a.out.h>
#include <link.h>
#include <elf.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include "../config.h"
#include "readelf.h"
#ifdef __GNUC__
void warn(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
void error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
#endif
char *___strtok = NULL;
/* For SunOS */
#ifndef PATH_MAX
#include <limits.h>
#define PATH_MAX _POSIX_PATH_MAX
#endif
/* For SunOS */
#ifndef N_MAGIC
#define N_MAGIC(exec) ((exec).a_magic & 0xffff)
#endif
#define EXIT_OK 0
#define EXIT_FATAL 128
char *prog = NULL;
int debug = 0; /* debug mode */
int verbose = 0; /* verbose mode */
int libmode = 0; /* library mode */
int nocache = 0; /* don't build cache */
int nolinks = 0; /* don't update links */
char *conffile = LDSO_CONF; /* default conf file */
char *cachefile = LDSO_CACHE; /* default cache file */
void cache_print(void);
void cache_dolib(const char *dir, const char *so, int libtype);
void cache_write(void);
void warn(const char *fmt, ...)
{
va_list ap;
if (verbose < 0)
return;
fflush(stdout); /* don't mix output and error messages */
fprintf(stderr, "%s: warning: ", prog);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
return;
}
void error(const char *fmt, ...)
{
va_list ap;
fflush(stdout); /* don't mix output and error messages */
fprintf(stderr, "%s: ", prog);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(EXIT_FATAL);
}
void *xmalloc(size_t size)
{
void *ptr;
if ((ptr = malloc(size)) == NULL)
error("out of memory");
return ptr;
}
char *xstrdup(const char *str)
{
char *ptr;
if ((ptr = strdup(str)) == NULL)
error("out of memory");
return ptr;
}
/* If shared library, return a malloced copy of the soname and set the
type, else return NULL.
expected_type should be either LIB_ANY or one of the following:-
LIB_DLL
LIB_ELF
LIB_ELF_LIBC5
LIB_ELF_LIBC6
If the lib is ELF and we can not deduce the type the type will
be set based on expected_type.
If the expected, actual/deduced types missmatch we display a warning
and use the actual/deduced type.
*/
char *is_shlib(const char *dir, const char *name, int *type,
int *islink, int expected_type)
{
char *good = NULL;
char *cp, *cp2;
FILE *file;
struct exec exec;
ElfW(Ehdr) *elf_hdr;
struct stat statbuf;
char buff[4096];
/* see if name is of the form libZ.so* */
if ((strncmp(name, "lib", 3) == 0 || strncmp(name, "ld-", 3) == 0) && \
name[strlen(name)-1] != '~' && (cp = strstr(name, ".so")))
{
/* find the start of the Vminor part, if any */
if (cp[3] == '.' && (cp2 = strchr(cp + 4, '.')))
cp = cp2;
else
cp = cp + strlen(cp);
/* construct the full path name */
sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ?
"/" : "", name);
/* first, make sure it's a regular file */
if (lstat(buff, &statbuf))
warn("can't lstat %s (%s), skipping", buff, strerror(errno));
else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
warn("%s is not a regular file or symlink, skipping", buff);
else
{
/* is it a regular file or a symlink */
*islink = S_ISLNK(statbuf.st_mode);
/* then try opening it */
if (!(file = fopen(buff, "rb")))
warn("can't open %s (%s), skipping", buff, strerror(errno));
else
{
/* now make sure it's a shared library */
if (fread(&exec, sizeof exec, 1, file) < 1)
warn("can't read header from %s, skipping", buff);
else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC)
{
elf_hdr = (ElfW(Ehdr) *) &exec;
if (elf_hdr->e_ident[0] != 0x7f ||
strncmp(&elf_hdr->e_ident[1], "ELF",3) != 0)
{
/* silently ignore linker scripts */
if (strncmp((char *)&exec, "/* GNU ld", 9) != 0)
warn("%s is not a shared library, skipping", buff);
}
else
{
/* always call readsoname to update type */
if(expected_type == LIB_DLL){
warn("%s is not an a.out library, its ELF!\n", buff);
expected_type=LIB_ANY;
}
*type = LIB_ELF;
good = readsoname(buff, file, expected_type, type,
elf_hdr->e_ident[EI_CLASS]);
if (good == NULL || *islink)
{
if (good != NULL)
free(good);
good = xstrdup(name);
}
else
{
/* if the soname does not match the filename,
issue a warning, but only in debug mode. */
int len = strlen(good);
if (debug && (strncmp(good, name, len) != 0 ||
(name[len] != '\0' && name[len] != '.')))
warn("%s has inconsistent soname (%s)",
buff, good);
}
}
}
else
{
if (*islink)
good = xstrdup(name);
else
{
good = xmalloc(cp - name + 1);
strncpy(good, name, cp - name);
good[cp - name] = '\0';
}
if(expected_type != LIB_ANY && expected_type != LIB_DLL)
{
warn("%s is not an ELF library, its an a.out DLL!", buff);
expected_type=LIB_ANY;
}
*type = LIB_DLL;
}
fclose(file);
}
}
}
return good;
}
/* update the symlink to new library */
void link_shlib(const char *dir, const char *file, const char *so)
{
int change = 1;
char libname[4096];
char linkname[4096];
struct stat libstat;
struct stat linkstat;
/* construct the full path names */
sprintf(libname, "%s/%s", dir, file);
sprintf(linkname, "%s/%s", dir, so);
/* see if a link already exists */
if (!stat(linkname, &linkstat))
{
/* now see if it's the one we want */
if (stat(libname, &libstat))
warn("can't stat %s (%s)", libname, strerror(errno));
else if (libstat.st_dev == linkstat.st_dev &&
libstat.st_ino == linkstat.st_ino)
change = 0;
}
/* then update the link, if required */
if (change > 0 && !nolinks)
{
if (!lstat(linkname, &linkstat))
{
if (!S_ISLNK(linkstat.st_mode))
{
warn("%s is not a symlink", linkname);
change = -1;
}
else if (remove(linkname))
{
warn("can't unlink %s (%s)", linkname, strerror(errno));
change = -1;
}
}
if (change > 0)
{
if (symlink(file, linkname))
{
warn("can't link %s to %s (%s)", linkname, file, strerror(errno));
change = -1;
}
}
}
/* some people like to know what we're doing */
if (verbose > 0)
printf("\t%s => %s%s\n", so, file,
change < 0 ? " (SKIPPED)" :
(change > 0 ? " (changed)" : ""));
return;
}
/* figure out which library is greater */
int libcmp(char *p1, char *p2)
{
while (*p1)
{
if (isdigit(*p1) && isdigit(*p2))
{
/* must compare this numerically */
int v1, v2;
v1 = strtoul(p1, &p1, 10);
v2 = strtoul(p2, &p2, 10);
if (v1 != v2)
return v1 - v2;
}
else if (isdigit(*p1) && !isdigit(*p2))
return 1;
else if (!isdigit(*p1) && isdigit(*p2))
return -1;
else if (*p1 != *p2)
return *p1 - *p2;
else
p1++, p2++;
}
return *p1 - *p2;
}
struct lib
{
char *so; /* soname of a library */
char *name; /* name of a library */
int libtype; /* type of a library */
int islink; /* is it a symlink */
struct lib *next; /* next library in list */
};
/* update all shared library links in a directory */
void scan_dir(const char *name)
{
DIR *dir;
struct dirent *ent;
char *so;
struct lib *lp, *libs = NULL;
int libtype, islink;
int expected_type = LIB_ANY;
char *t;
/* Check for an embedded expected type */
t=strrchr(name, '=');
if( t )
{
*t++ = '\0'; /* Skip = char */
if(strcasecmp(t, "libc4") == 0)
{
expected_type = LIB_DLL;
}
else
{
if(strcasecmp(t, "libc5") == 0)
{
expected_type = LIB_ELF_LIBC5;
}
else
{
if(strcasecmp(t, "libc6") == 0)
{
expected_type = LIB_ELF_LIBC6;
}
else
{
warn("Unknown type field '%s' for dir '%s' - ignored\n", t, name);
expected_type = LIB_ANY;
}
}
}
}
/* let 'em know what's going on */
if (verbose > 0)
printf("%s:\n", name);
/* if we can't open it, we can't do anything */
if ((dir = opendir(name)) == NULL)
{
warn("can't open %s (%s), skipping", name, strerror(errno));
return;
}
/* yes, we have to look at every single file */
while ((ent = readdir(dir)) != NULL)
{
/* if it's not a shared library, don't bother */
if ((so = is_shlib(name, ent->d_name, &libtype, &islink, expected_type)) == NULL)
continue;
/* have we already seen one with the same so name? */
for (lp = libs; lp; lp = lp->next)
{
if (strcmp(so, lp->so) == 0)
{
/* we have, which one do we want to use? */
if ((!islink && lp->islink) ||
(islink == lp->islink &&
libcmp(ent->d_name, lp->name) > 0))
{
/* let's use the new one */
free(lp->name);
lp->name = xstrdup(ent->d_name);
lp->libtype = libtype;
lp->islink = islink;
}
break;
}
}
/* congratulations, you're the first one we've seen */
if (!lp)
{
lp = xmalloc(sizeof *lp);
lp->so = xstrdup(so);
lp->name = xstrdup(ent->d_name);
lp->libtype = libtype;
lp->islink = islink;
lp->next = libs;
libs = lp;
}
free(so);
}
/* don't need this any more */
closedir(dir);
/* now we have all the latest libs, update the links */
for (lp = libs; lp; lp = lp->next)
{
if (!lp->islink)
link_shlib(name, lp->name, lp->so);
if (!nocache)
cache_dolib(name, lp->so, lp->libtype);
}
/* always try to clean up after ourselves */
while (libs)
{
lp = libs->next;
free(libs->so);
free(libs->name);
free(libs);
libs = lp;
}
return;
}
/* return the list of system-specific directories */
char *get_extpath(void)
{
char *res = NULL, *cp;
FILE *file;
struct stat stat;
if ((file = fopen(conffile, "r")) != NULL)
{
fstat(fileno(file), &stat);
res = xmalloc(stat.st_size + 1);
fread(res, 1, stat.st_size, file);
fclose(file);
res[stat.st_size] = '\0';
/* convert comments fo spaces */
for (cp = res; *cp; /*nada*/) {
if (*cp == '#') {
do
*cp++ = ' ';
while (*cp && *cp != '\n');
} else {
cp++;
}
}
}
return res;
}
void usage(void)
{
fprintf(stderr,
"ldconfig - update shared library symlinks\n"
"\n"
"usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...\n"
" ldconfig -l [-Dv] lib ...\n"
" ldconfig -p\n"
"\t-D:\t\tdebug mode, don't update links\n"
"\t-v:\t\tverbose mode, print things as we go\n"
"\t-q:\t\tquiet mode, don't print warnings\n"
"\t-n:\t\tdon't process standard directories\n"
"\t-N:\t\tdon't update the library cache\n"
"\t-X:\t\tdon't update the library links\n"
"\t-l:\t\tlibrary mode, manually link libraries\n"
"\t-p:\t\tprint the current library cache\n"
"\t-f conf :\tuse conf instead of %s\n"
"\t-C cache:\tuse cache instead of %s\n"
"\t-r root :\tfirst, do a chroot to the indicated directory\n"
"\tdir ... :\tdirectories to process\n"
"\tlib ... :\tlibraries to link\n"
"\n"
"Copyright 1994-2000 David Engel and Mitch D'Souza\n",
LDSO_CONF, LDSO_CACHE
);
exit(EXIT_FATAL);
}
int main(int argc, char **argv)
{
int i, c;
int nodefault = 0;
int printcache = 0;
char *cp, *dir, *so;
char *extpath;
int libtype, islink;
char *chroot_dir = NULL;
prog = argv[0];
opterr = 0;
while ((c = getopt(argc, argv, "DvqnNXlpf:C:r:")) != EOF)
switch (c)
{
case 'D':
debug = 1; /* debug mode */
nocache = 1;
nolinks = 1;
verbose = 1;
break;
case 'v':
verbose = 1; /* verbose mode */
break;
case 'q':
if (verbose <= 0)
verbose = -1; /* quiet mode */
break;
case 'n':
nodefault = 1; /* no default dirs */
nocache = 1;
break;
case 'N':
nocache = 1; /* don't build cache */
break;
case 'X':
nolinks = 1; /* don't update links */
break;
case 'l':
libmode = 1; /* library mode */
break;
case 'p':
printcache = 1; /* print cache */
break;
case 'f':
conffile = optarg; /* alternate conf file */
break;
case 'C':
cachefile = optarg; /* alternate cache file */
break;
case 'r':
chroot_dir = optarg;
break;
default:
usage();
break;
/* THE REST OF THESE ARE UNDOCUMENTED AND MAY BE REMOVED
IN FUTURE VERSIONS. */
}
if (chroot_dir && *chroot_dir) {
if (chroot(chroot_dir) < 0)
error("couldn't chroot to %s (%s)", chroot_dir, strerror(errno));
if (chdir("/") < 0)
error("couldn't chdir to / (%s)", strerror(errno));
}
/* allow me to introduce myself, hi, my name is ... */
if (verbose > 0)
printf("%s: version %s\n", argv[0], VERSION);
if (printcache)
{
/* print the cache -- don't you trust me? */
cache_print();
exit(EXIT_OK);
}
else if (libmode)
{
/* so you want to do things manually, eh? */
/* ok, if you're so smart, which libraries do we link? */
for (i = optind; i < argc; i++)
{
/* split into directory and file parts */
if (!(cp = strrchr(argv[i], '/')))
{
dir = "."; /* no dir, only a filename */
cp = argv[i];
}
else
{
if (cp == argv[i])
dir = "/"; /* file in root directory */
else
dir = argv[i];
*cp++ = '\0'; /* neither of the above */
}
/* we'd better do a little bit of checking */
if ((so = is_shlib(dir, cp, &libtype, &islink, LIB_ANY)) == NULL)
error("%s%s%s is not a shared library", dir,
(*dir && strcmp(dir, "/")) ? "/" : "", cp);
/* so far, so good, maybe he knows what he's doing */
link_shlib(dir, cp, so);
}
}
else
{
/* the lazy bum want's us to do all the work for him */
/* don't cache dirs on the command line */
int nocache_save = nocache;
nocache = 1;
/* OK, which directories should we do? */
for (i = optind; i < argc; i++)
scan_dir(argv[i]);
/* restore the desired caching state */
nocache = nocache_save;
/* look ma, no defaults */
if (!nodefault)
{
/* I guess the defaults aren't good enough */
if ((extpath = get_extpath()))
{
for (cp = strtok(extpath, DIR_SEP); cp;
cp = strtok(NULL, DIR_SEP))
scan_dir(cp);
free(extpath);
}
#ifdef UCLIBC_DEVEL
scan_dir(UCLIBC_INSTALL_DIR"/lib");
#else
/* everybody needs these, don't they? */
scan_dir("/usr/lib");
scan_dir("/lib");
#endif
}
if (!nocache)
cache_write();
}
exit(EXIT_OK);
}
typedef struct liblist
{
int flags;
int sooffset;
int liboffset;
char *soname;
char *libname;
struct liblist *next;
} liblist_t;
static header_t magic = { LDSO_CACHE_MAGIC, LDSO_CACHE_VER, 0 };
static liblist_t *lib_head = NULL;
static int liblistcomp(liblist_t *x, liblist_t *y)
{
int res;
if ((res = libcmp(x->soname, y->soname)) == 0)
{
res = libcmp(strrchr(x->libname, '/') + 1,
strrchr(y->libname, '/') + 1);
}
return res;
}
void cache_dolib(const char *dir, const char *so, int libtype)
{
char fullpath[PATH_MAX];
liblist_t *new_lib, *cur_lib;
magic.nlibs++;
sprintf(fullpath, "%s/%s", dir, so);
new_lib = xmalloc(sizeof (liblist_t));
new_lib->flags = libtype;
new_lib->soname = xstrdup(so);
new_lib->libname = xstrdup(fullpath);
if (lib_head == NULL || liblistcomp(new_lib, lib_head) > 0)
{
new_lib->next = lib_head;
lib_head = new_lib;
}
else
{
for (cur_lib = lib_head; cur_lib->next != NULL &&
liblistcomp(new_lib, cur_lib->next) <= 0;
cur_lib = cur_lib->next)
/* nothing */;
new_lib->next = cur_lib->next;
cur_lib->next = new_lib;
}
}
void cache_write(void)
{
int cachefd;
int stroffset = 0;
char tempfile[4096];
liblist_t *cur_lib;
if (!magic.nlibs)
return;
sprintf(tempfile, "%s~", cachefile);
if (unlink(tempfile) && errno != ENOENT)
error("can't unlink %s (%s)", tempfile, strerror(errno));
if ((cachefd = creat(tempfile, 0644)) < 0)
error("can't create %s (%s)", tempfile, strerror(errno));
if (write(cachefd, &magic, sizeof (header_t)) != sizeof (header_t))
error("can't write %s (%s)", tempfile, strerror(errno));
for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
{
cur_lib->sooffset = stroffset;
stroffset += strlen(cur_lib->soname) + 1;
cur_lib->liboffset = stroffset;
stroffset += strlen(cur_lib->libname) + 1;
if (write(cachefd, cur_lib, sizeof (libentry_t)) !=
sizeof (libentry_t))
error("can't write %s (%s)", tempfile, strerror(errno));
}
for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
{
if (write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1)
!= strlen(cur_lib->soname) + 1)
error("can't write %s (%s)", tempfile, strerror(errno));
if (write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1)
!= strlen(cur_lib->libname) + 1)
error("can't write %s (%s)", tempfile, strerror(errno));
}
if (close(cachefd))
error("can't close %s (%s)", tempfile, strerror(errno));
if (chmod(tempfile, 0644))
error("can't chmod %s (%s)", tempfile, strerror(errno));
if (rename(tempfile, cachefile))
error("can't rename %s (%s)", tempfile, strerror(errno));
}
void cache_print(void)
{
caddr_t c;
struct stat st;
int fd = 0;
char *strs;
header_t *header;
libentry_t *libent;
if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY))<0)
error("can't read %s (%s)", cachefile, strerror(errno));
if ((c = mmap(0,st.st_size, PROT_READ, MAP_SHARED ,fd, 0)) == (caddr_t)-1)
error("can't map %s (%s)", cachefile, strerror(errno));
close(fd);
if (memcmp(((header_t *)c)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
error("%s cache corrupt", cachefile);
if (memcmp(((header_t *)c)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
error("wrong cache version - expected %s", LDSO_CACHE_VER);
header = (header_t *)c;
libent = (libentry_t *)(c + sizeof (header_t));
strs = (char *)&libent[header->nlibs];
printf("%d libs found in cache `%s' (version %s)\n",
header->nlibs, cachefile, LDSO_CACHE_VER);
for (fd = 0; fd < header->nlibs; fd++)
{
printf("\t%s ", strs + libent[fd].sooffset);
switch (libent[fd].flags & ~LIB_ELF64)
{
case LIB_DLL:
printf("(libc4)");
break;
case LIB_ELF:
printf("(ELF%s)", libent[fd].flags & LIB_ELF64 ? "/64" : "");
break;
case LIB_ELF_LIBC5:
case LIB_ELF_LIBC6:
printf("(libc%d%s)", (libent[fd].flags & ~LIB_ELF64) + 3,
libent[fd].flags & LIB_ELF64 ? "/64" : "");
break;
default:
printf("(unknown)");
break;
}
printf(" => %s\n", strs + libent[fd].liboffset);
}
munmap (c,st.st_size);
}

310
ldso/util/ldd.c Normal file
View File

@@ -0,0 +1,310 @@
/*
* ldd - print shared library dependencies
*
* usage: ldd [-vVdr] prog ...
* -v: print ldd version
* -V: print ld.so version
* -d: Perform relocations and report any missing functions. (ELF only).
* -r: Perform relocations for both data objects and functions, and
* report any missing objects (ELF only).
* prog ...: programs to check
*
* Copyright 1993-2000, David Engel
*
* This program may be used for any purpose as long as this
* copyright notice is kept.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <a.out.h>
#include <errno.h>
#include <sys/wait.h>
#include <linux/elf.h>
#include "../config.h"
#include "readelf.h"
#ifdef __GNUC__
void warn(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
void error(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
#endif
char *prog = NULL;
void warn(char *fmt, ...)
{
va_list ap;
fflush(stdout); /* don't mix output and error messages */
fprintf(stderr, "%s: warning: ", prog);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
return;
}
void error(char *fmt, ...)
{
va_list ap;
fflush(stdout); /* don't mix output and error messages */
fprintf(stderr, "%s: ", prog);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
void *xmalloc(size_t size)
{
void *ptr;
if ((ptr = malloc(size)) == NULL)
error("out of memory");
return ptr;
}
char *xstrdup(char *str)
{
char *ptr;
if ((ptr = strdup(str)) == NULL)
error("out of memory");
return ptr;
}
/* see if prog is a binary file */
int is_bin(char *argv0, char *prog)
{
int res = 0;
FILE *file;
struct exec exec;
char *cp;
int libtype;
/* must be able to open it for reading */
if ((file = fopen(prog, "rb")) == NULL)
fprintf(stderr, "%s: can't open %s (%s)\n", argv0, prog,
strerror(errno));
else
{
/* then see if it's Z, Q or OMAGIC */
if (fread(&exec, sizeof exec, 1, file) < 1)
fprintf(stderr, "%s: can't read header from %s\n", argv0, prog);
else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
N_MAGIC(exec) != OMAGIC)
{
struct elfhdr elf_hdr;
rewind(file);
fread(&elf_hdr, sizeof elf_hdr, 1, file);
if (elf_hdr.e_ident[0] != 0x7f ||
strncmp(elf_hdr.e_ident+1, "ELF", 3) != 0)
fprintf(stderr, "%s: %s is not a.out or ELF\n", argv0, prog);
else
{
struct elf_phdr phdr;
int i;
/* Check its an exectuable, library or other */
switch (elf_hdr.e_type)
{
case ET_EXEC:
res = 3;
/* then determine if it is dynamic ELF */
for (i=0; i<elf_hdr.e_phnum; i++)
{
fread(&phdr, sizeof phdr, 1, file);
if (phdr.p_type == PT_DYNAMIC)
{
res = 2;
break;
}
}
break;
case ET_DYN:
if ((cp = readsoname(prog, file, LIB_ANY, &libtype,
elf_hdr.e_ident[EI_CLASS])) != NULL)
free(cp);
if (libtype == LIB_ELF_LIBC5)
res = 5;
else
res = 4;
break;
default:
res = 0;
break;
}
}
}
else
res = 1; /* looks good */
fclose(file);
}
return res;
}
int main(int argc, char **argv, char **envp)
{
int i;
int vprinted = 0;
int resolve = 0;
int bind = 0;
int bintype;
char *ld_preload;
int status = 0;
/* this must be volatile to work with -O, GCC bug? */
volatile loadptr loader = (loadptr)LDSO_ADDR;
prog = argv[0];
while ((i = getopt(argc, argv, "drvV")) != EOF)
switch (i)
{
case 'v':
/* print our version number */
printf("%s: version %s\n", argv[0], VERSION);
vprinted = 1;
break;
case 'd':
bind = 1;
break;
case 'r':
resolve = 1;
break;
case 'V':
/* print the version number of ld.so */
if (uselib(LDSO_IMAGE))
{
fprintf(stderr, "%s: can't load dynamic linker %s (%s)\n",
argv[0], LDSO_IMAGE, strerror(errno));
exit(1);
}
loader(FUNC_VERS, NULL);
vprinted = 1;
break;
}
/* must specify programs if -v or -V not used */
if (optind >= argc && !vprinted)
{
printf("usage: %s [-vVdr] prog ...\n", argv[0]);
exit(0);
}
/* setup the environment for ELF binaries */
putenv("LD_TRACE_LOADED_OBJECTS=1");
if (resolve || bind)
putenv("LD_BIND_NOW=1");
if (resolve)
putenv("LD_WARN=1");
ld_preload = getenv("LD_PRELOAD");
/* print the dependencies for each program */
for (i = optind; i < argc; i++)
{
pid_t pid;
char buff[1024];
/* make sure it's a binary file */
if (!(bintype = is_bin(argv[0], argv[i])))
{
status = 1;
continue;
}
/* print the program name if doing more than one */
if (optind < argc-1)
{
printf("%s:\n", argv[i]);
fflush(stdout);
}
/* no need to fork/exec for static ELF program */
if (bintype == 3)
{
printf("\tstatically linked (ELF)\n");
continue;
}
/* now fork and exec prog with argc = 0 */
if ((pid = fork()) < 0)
{
fprintf(stderr, "%s: can't fork (%s)\n", argv[0], strerror(errno));
exit(1);
}
else if (pid == 0)
{
switch (bintype)
{
case 1: /* a.out */
/* save the name in the enviroment, ld.so may need it */
snprintf(buff, sizeof buff, "%s=%s", LDD_ARGV0, argv[i]);
putenv(buff);
execl(argv[i], NULL);
break;
case 2: /* ELF program */
execl(argv[i], argv[i], NULL);
break;
case 4: /* ELF libc6 library */
/* try to use /lib/ld-linux.so.2 first */
#if !defined(__mc68000__)
execl("/lib/ld-linux.so.2", "/lib/ld-linux.so.2",
"--list", argv[i], NULL);
#else
execl("/lib/ld.so.1", "/lib/ld.so.1",
"--list", argv[i], NULL);
#endif
/* fall through */
case 5: /* ELF libc5 library */
/* if that fails, add library to LD_PRELOAD and
then execute lddstub */
if (ld_preload && *ld_preload)
snprintf(buff, sizeof buff, "LD_PRELOAD=%s:%s%s",
ld_preload, *argv[i] == '/' ? "" : "./", argv[i]);
else
snprintf(buff, sizeof buff, "LD_PRELOAD=%s%s",
*argv[i] == '/' ? "" : "./", argv[i]);
putenv(buff);
execl(LDDSTUB, argv[i], NULL);
break;
default:
fprintf(stderr, "%s: internal error, bintype = %d\n",
argv[0], bintype);
exit(1);
}
fprintf(stderr, "%s: can't execute %s (%s)\n", argv[0], argv[i],
strerror(errno));
exit(1);
}
else
{
/* then wait for it to complete */
int status;
if (waitpid(pid, &status, 0) != pid)
{
fprintf(stderr, "%s: error waiting for %s (%s)\n", argv[0],
argv[i], strerror(errno));
}
else if (WIFSIGNALED(status))
{
fprintf(stderr, "%s: %s exited with signal %d\n", argv[0],
argv[i], WTERMSIG(status));
}
}
}
exit(status);
}

42
ldso/util/lddstub.S Normal file
View File

@@ -0,0 +1,42 @@
.text
.globl main
.globl exit
main:
exit:
#if defined(__i386__)
movl $1,%eax
movl $0,%ebx
int $0x80
#elif defined(__mc68000__)
movel #1,%d0
clrl %d1
trap #0
#elif defined(__sparc__)
mov 1,%g1
mov 0,%o0
t 0x10
#else
#error Only know how to support i386, m68k and sparc architectures
#endif
.globl atexit
.globl __libc_init
.globl __setfpucw
atexit:
__libc_init:
__setfpucw:
#if defined(__i386__)
ret
#elif defined(__mc68000__)
rts
#elif defined(__sparc__)
ret
nop
#else
#error Only know how to support i386, m68k and sparc architectures
#endif
.data
.globl __fpu_control
__fpu_control:
.long 0

61
ldso/util/readelf.c Normal file
View File

@@ -0,0 +1,61 @@
/* adapted from Eric Youngdale's readelf program */
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <link.h>
#include <elf.h>
#include <unistd.h>
#include "../config.h"
#include "readelf.h"
#include <sys/types.h>
void warn(char *fmt, ...);
char *xstrdup(char *);
struct needed_tab
{
char *soname;
int type;
};
struct needed_tab needed_tab[] = {
{ "libc.so.5", LIB_ELF_LIBC5 },
{ "libm.so.5", LIB_ELF_LIBC5 },
{ "libdl.so.1", LIB_ELF_LIBC5 },
{ "libc.so.6", LIB_ELF_LIBC6 },
{ "libm.so.6", LIB_ELF_LIBC6 },
{ "libdl.so.2", LIB_ELF_LIBC6 },
{ NULL, LIB_ELF }
};
char *readsoname(char *name, FILE *infile, int expected_type,
int *type, int elfclass)
{
char *res;
if (elfclass == ELFCLASS32)
res = readsoname32(name, infile, expected_type, type);
else
{
res = readsoname64(name, infile, expected_type, type);
#if 0
*type |= LIB_ELF64;
#endif
}
return res;
}
#undef __ELF_NATIVE_CLASS
#undef readsonameXX
#define readsonameXX readsoname32
#define __ELF_NATIVE_CLASS 32
#include "readelf2.c"
#undef __ELF_NATIVE_CLASS
#undef readsonameXX
#define readsonameXX readsoname64
#define __ELF_NATIVE_CLASS 64
#include "readelf2.c"

4
ldso/util/readelf.h Normal file
View File

@@ -0,0 +1,4 @@
char *readsoname(char *name, FILE *file, int expected_type,
int *type, int elfclass);
char *readsoname32(char *name, FILE *file, int expected_type, int *type);
char *readsoname64(char *name, FILE *file, int expected_type, int *type);

115
ldso/util/readelf2.c Normal file
View File

@@ -0,0 +1,115 @@
char *readsonameXX(char *name, FILE *infile, int expected_type, int *type)
{
ElfW(Ehdr) *epnt;
ElfW(Phdr) *ppnt;
int i, j;
char *header;
ElfW(Word) dynamic_addr = 0;
ElfW(Word) dynamic_size = 0;
unsigned long page_size = getpagesize();
ElfW(Word) strtab_val = 0;
ElfW(Word) needed_val;
ElfW(Sword) loadaddr = -1;
ElfW(Dyn) *dpnt;
struct stat st;
char *needed;
char *soname = NULL;
int multi_libcs = 0;
if(expected_type == LIB_DLL)
{
warn("%s does not match type specified for directory!", name);
expected_type = LIB_ANY;
}
*type = LIB_ELF;
if (fstat(fileno(infile), &st))
return NULL;
header = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fileno(infile), 0);
if (header == (caddr_t)-1)
return NULL;
epnt = (ElfW(Ehdr) *)header;
if ((char *)(epnt+1) > (char *)(header + st.st_size))
goto skip;
ppnt = (ElfW(Phdr) *)&header[epnt->e_phoff];
if ((char *)ppnt < (char *)header ||
(char *)(ppnt+epnt->e_phnum) > (char *)(header + st.st_size))
goto skip;
for(i = 0; i < epnt->e_phnum; i++)
{
if (loadaddr == -1 && ppnt->p_type == PT_LOAD)
loadaddr = (ppnt->p_vaddr & ~(page_size-1)) -
(ppnt->p_offset & ~(page_size-1));
if(ppnt->p_type == 2)
{
dynamic_addr = ppnt->p_offset;
dynamic_size = ppnt->p_filesz;
};
ppnt++;
};
dpnt = (ElfW(Dyn) *) &header[dynamic_addr];
dynamic_size = dynamic_size / sizeof(ElfW(Dyn));
if ((char *)dpnt < (char *)header ||
(char *)(dpnt+dynamic_size) > (char *)(header + st.st_size))
goto skip;
while (dpnt->d_tag != DT_NULL)
{
if (dpnt->d_tag == DT_STRTAB)
strtab_val = dpnt->d_un.d_val;
dpnt++;
};
if (!strtab_val)
goto skip;
dpnt = (ElfW(Dyn) *) &header[dynamic_addr];
while (dpnt->d_tag != DT_NULL)
{
if (dpnt->d_tag == DT_SONAME || dpnt->d_tag == DT_NEEDED)
{
needed_val = dpnt->d_un.d_val;
if (needed_val + strtab_val - loadaddr >= 0 ||
needed_val + strtab_val - loadaddr < st.st_size)
{
needed = (char *) (header - loadaddr + strtab_val + needed_val);
if (dpnt->d_tag == DT_SONAME)
soname = xstrdup(needed);
for (j = 0; needed_tab[j].soname != NULL; j++)
{
if (strcmp(needed, needed_tab[j].soname) == 0)
{
if (*type != LIB_ELF && *type != needed_tab[j].type)
multi_libcs = 1;
*type = needed_tab[j].type;
}
}
}
}
dpnt++;
};
if (multi_libcs)
warn("%s appears to be for multiple libc's", name);
/* If we could not deduce the libc type, and we know what to expect, set the type */
if(*type == LIB_ELF && expected_type != LIB_ANY) *type = expected_type;
if(expected_type != LIB_ANY && expected_type != LIB_ELF &&
expected_type != *type)
{
warn("%s does not match type specified for directory!", name);
}
skip:
munmap(header, st.st_size);
return soname;
}