mirror of
https://git.busybox.net/uClibc
synced 2025-10-14 01:32:00 +08:00
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:
49
ldso/COPYRIGHT
Normal file
49
ldso/COPYRIGHT
Normal 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
13
ldso/Makefile
Normal 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
860
ldso/README
Normal 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
59
ldso/config.h
Normal 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
39
ldso/ldso/Makefile
Normal 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
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
588
ldso/ldso/dl-elf.c
Normal 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
284
ldso/ldso/dl-hash.c
Normal 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
284
ldso/ldso/hash.c
Normal 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
113
ldso/ldso/hash.h
Normal 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
|
||||
|
82
ldso/ldso/i386/dl-sysdep.h
Normal file
82
ldso/ldso/i386/dl-sysdep.h
Normal 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
321
ldso/ldso/i386/elfinterp.c
Normal 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;
|
||||
}
|
||||
|
||||
|
82
ldso/ldso/i386/ld_sysdep.h
Normal file
82
ldso/ldso/i386/ld_sysdep.h
Normal 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
55
ldso/ldso/i386/resolve.S
Normal 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
82
ldso/ldso/i386/sysdep.h
Normal 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
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
113
ldso/ldso/ld_hash.h
Normal 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
112
ldso/ldso/ld_string.h
Normal 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
108
ldso/ldso/ld_syscall.h
Normal 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
1005
ldso/ldso/ldso.c
Normal file
File diff suppressed because it is too large
Load Diff
37
ldso/ldso/link.h
Normal file
37
ldso/ldso/link.h
Normal 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
137
ldso/ldso/linuxelf.h
Normal 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))
|
||||
|
87
ldso/ldso/m68k/dl-sysdep.h
Normal file
87
ldso/ldso/m68k/dl-sysdep.h
Normal 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
358
ldso/ldso/m68k/elfinterp.c
Normal 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;
|
||||
}
|
87
ldso/ldso/m68k/ld_sysdep.h
Normal file
87
ldso/ldso/m68k/ld_sysdep.h
Normal 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
29
ldso/ldso/m68k/resolve.S
Normal 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
87
ldso/ldso/m68k/sysdep.h
Normal 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
588
ldso/ldso/readelflib1.c
Normal 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
5
ldso/ldso/sparc/DEFS.h
Normal 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
131
ldso/ldso/sparc/dl-sysdep.h
Normal 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
355
ldso/ldso/sparc/elfinterp.c
Normal 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
131
ldso/ldso/sparc/ld_sysdep.h
Normal 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
25
ldso/ldso/sparc/resolve.S
Normal 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
369
ldso/ldso/sparc/sdiv.S
Normal 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
131
ldso/ldso/sparc/sysdep.h
Normal 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
351
ldso/ldso/sparc/udiv.S
Normal 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
153
ldso/ldso/sparc/umul.S
Normal 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
352
ldso/ldso/sparc/urem.S
Normal 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
112
ldso/ldso/string.h
Normal 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
108
ldso/ldso/syscall.h
Normal 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
290
ldso/ldso/vsprintf.c
Normal 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
31
ldso/libdl/Makefile
Normal 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
41
ldso/libdl/dlfcn.h
Normal 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
648
ldso/libdl/dlib.c
Normal 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
648
ldso/libdl/libdl.c
Normal 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
11
ldso/man/Makefile
Normal 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
218
ldso/man/dlopen.3
Normal 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
113
ldso/man/ld.so.8
Normal 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
411
ldso/man/ld.so.texi
Normal 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
189
ldso/man/ldconfig.8
Normal 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
59
ldso/man/ldd.1
Normal 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
38
ldso/util/Makefile
Normal 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
837
ldso/util/ldconfig.c
Normal 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
310
ldso/util/ldd.c
Normal 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
42
ldso/util/lddstub.S
Normal 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
61
ldso/util/readelf.c
Normal 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
4
ldso/util/readelf.h
Normal 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
115
ldso/util/readelf2.c
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user