From 3472f0c34f6e1cb2900d70157aadd2006703cb4d Mon Sep 17 00:00:00 2001 From: pefo Date: Wed, 18 Sep 1996 08:15:16 +0000 Subject: [PATCH] OK, this is the dynamic loader for the MIPS. It's a hack, it's GPL'd, its just ugly, but it works. So we stick with it right now... --- gnu/libexec/ld.so/COPYRIGHT | 49 ++ gnu/libexec/ld.so/Makefile | 5 + gnu/libexec/ld.so/README | 311 ++++++++ gnu/libexec/ld.so/config.h | 46 ++ gnu/libexec/ld.so/ld.so/Makefile | 22 + gnu/libexec/ld.so/ld.so/boot1.c | 848 +++++++++++++++++++++ gnu/libexec/ld.so/ld.so/hash.c | 225 ++++++ gnu/libexec/ld.so/ld.so/hash.h | 100 +++ gnu/libexec/ld.so/ld.so/i386/Makefile | 49 ++ gnu/libexec/ld.so/ld.so/i386/elfinterp.c | 328 ++++++++ gnu/libexec/ld.so/ld.so/i386/resolve.S | 51 ++ gnu/libexec/ld.so/ld.so/i386/string.h | 439 +++++++++++ gnu/libexec/ld.so/ld.so/i386/syscall.h | 281 +++++++ gnu/libexec/ld.so/ld.so/i386/sysdep.h | 90 +++ gnu/libexec/ld.so/ld.so/ld.so.8 | 172 +++++ gnu/libexec/ld.so/ld.so/m68k/Makefile | 49 ++ gnu/libexec/ld.so/ld.so/m68k/elfinterp.c | 360 +++++++++ gnu/libexec/ld.so/ld.so/m68k/resolve.S | 29 + gnu/libexec/ld.so/ld.so/m68k/string.h | 303 ++++++++ gnu/libexec/ld.so/ld.so/m68k/syscall.h | 182 +++++ gnu/libexec/ld.so/ld.so/m68k/sysdep.h | 87 +++ gnu/libexec/ld.so/ld.so/mips/Makefile | 49 ++ gnu/libexec/ld.so/ld.so/mips/elf-machine.h | 27 + gnu/libexec/ld.so/ld.so/mips/elf.h | 610 +++++++++++++++ gnu/libexec/ld.so/ld.so/mips/elf_abi.h | 343 +++++++++ gnu/libexec/ld.so/ld.so/mips/elfinterp.c | 449 +++++++++++ gnu/libexec/ld.so/ld.so/mips/link.h | 247 ++++++ gnu/libexec/ld.so/ld.so/mips/string.h | 303 ++++++++ gnu/libexec/ld.so/ld.so/mips/syscall.h | 201 +++++ gnu/libexec/ld.so/ld.so/mips/sysdep.h | 75 ++ gnu/libexec/ld.so/ld.so/readelflib1.c | 470 ++++++++++++ gnu/libexec/ld.so/ld.so/sparc/Makefile | 49 ++ gnu/libexec/ld.so/ld.so/sparc/elfinterp.c | 339 ++++++++ gnu/libexec/ld.so/ld.so/sparc/resolve.S | 25 + gnu/libexec/ld.so/ld.so/sparc/string.h | 326 ++++++++ gnu/libexec/ld.so/ld.so/sparc/syscall.h | 249 ++++++ gnu/libexec/ld.so/ld.so/sparc/sysdep.h | 126 +++ gnu/libexec/ld.so/ld.so/vsprintf.c | 238 ++++++ gnu/libexec/ld.so/ldconfig/Makefile | 11 + gnu/libexec/ld.so/ldconfig/ld.so.conf | 2 + gnu/libexec/ld.so/ldconfig/ldconfig.8 | 142 ++++ gnu/libexec/ld.so/ldconfig/ldconfig.c | 658 ++++++++++++++++ gnu/libexec/ld.so/ldconfig/readelf.c | 86 +++ 43 files changed, 9051 insertions(+) create mode 100644 gnu/libexec/ld.so/COPYRIGHT create mode 100644 gnu/libexec/ld.so/Makefile create mode 100644 gnu/libexec/ld.so/README create mode 100644 gnu/libexec/ld.so/config.h create mode 100644 gnu/libexec/ld.so/ld.so/Makefile create mode 100644 gnu/libexec/ld.so/ld.so/boot1.c create mode 100644 gnu/libexec/ld.so/ld.so/hash.c create mode 100644 gnu/libexec/ld.so/ld.so/hash.h create mode 100644 gnu/libexec/ld.so/ld.so/i386/Makefile create mode 100644 gnu/libexec/ld.so/ld.so/i386/elfinterp.c create mode 100644 gnu/libexec/ld.so/ld.so/i386/resolve.S create mode 100644 gnu/libexec/ld.so/ld.so/i386/string.h create mode 100644 gnu/libexec/ld.so/ld.so/i386/syscall.h create mode 100644 gnu/libexec/ld.so/ld.so/i386/sysdep.h create mode 100644 gnu/libexec/ld.so/ld.so/ld.so.8 create mode 100644 gnu/libexec/ld.so/ld.so/m68k/Makefile create mode 100644 gnu/libexec/ld.so/ld.so/m68k/elfinterp.c create mode 100644 gnu/libexec/ld.so/ld.so/m68k/resolve.S create mode 100644 gnu/libexec/ld.so/ld.so/m68k/string.h create mode 100644 gnu/libexec/ld.so/ld.so/m68k/syscall.h create mode 100644 gnu/libexec/ld.so/ld.so/m68k/sysdep.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/Makefile create mode 100644 gnu/libexec/ld.so/ld.so/mips/elf-machine.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/elf.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/elf_abi.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/elfinterp.c create mode 100644 gnu/libexec/ld.so/ld.so/mips/link.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/string.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/syscall.h create mode 100644 gnu/libexec/ld.so/ld.so/mips/sysdep.h create mode 100644 gnu/libexec/ld.so/ld.so/readelflib1.c create mode 100644 gnu/libexec/ld.so/ld.so/sparc/Makefile create mode 100644 gnu/libexec/ld.so/ld.so/sparc/elfinterp.c create mode 100644 gnu/libexec/ld.so/ld.so/sparc/resolve.S create mode 100644 gnu/libexec/ld.so/ld.so/sparc/string.h create mode 100644 gnu/libexec/ld.so/ld.so/sparc/syscall.h create mode 100644 gnu/libexec/ld.so/ld.so/sparc/sysdep.h create mode 100644 gnu/libexec/ld.so/ld.so/vsprintf.c create mode 100644 gnu/libexec/ld.so/ldconfig/Makefile create mode 100644 gnu/libexec/ld.so/ldconfig/ld.so.conf create mode 100644 gnu/libexec/ld.so/ldconfig/ldconfig.8 create mode 100644 gnu/libexec/ld.so/ldconfig/ldconfig.c create mode 100644 gnu/libexec/ld.so/ldconfig/readelf.c diff --git a/gnu/libexec/ld.so/COPYRIGHT b/gnu/libexec/ld.so/COPYRIGHT new file mode 100644 index 00000000000..37d2780d1f7 --- /dev/null +++ b/gnu/libexec/ld.so/COPYRIGHT @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1994 Eric Youngdale, Peter MacDonald, David Engel, + * Hongjiu Lu and Mitch D'Souza + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Notice of general intent: + * + * The linux operating system generally contains large amounts of code + * that fall under the GNU General Public License, or GPL for short. + * This file contains source code that by it's very nature would always + * be linked with an application program, and because of this a GPL + * type of copyright on this file would place restrictions upon the + * distribution of binary-only commercial software. Since the goal of + * the Linux project as a whole is not to discourage the development and + * distribution of commercial software for Linux, this file has been + * placed under a more relaxed BSD-style of copyright. + * + * It is the general understanding of the above contributors that a + * program executable linked to a library containing code that falls + * under the GPL or GLPL style of license is not subject to the terms of + * the GPL or GLPL license if the program executable(s) that are supplied + * are linked to a shared library form of the GPL or GLPL library, and as + * long as the form of the shared library is such that it is possible for + * the end user to modify and rebuild the library and use it in + * conjunction with the program executable. + */ diff --git a/gnu/libexec/ld.so/Makefile b/gnu/libexec/ld.so/Makefile new file mode 100644 index 00000000000..ea87f2cf988 --- /dev/null +++ b/gnu/libexec/ld.so/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 1996/09/18 08:15:19 pefo Exp $ + +SUBDIR= ldconfig ld.so + +.include diff --git a/gnu/libexec/ld.so/README b/gnu/libexec/ld.so/README new file mode 100644 index 00000000000..51bcc51a9c5 --- /dev/null +++ b/gnu/libexec/ld.so/README @@ -0,0 +1,311 @@ +This package contains my shared, dynamic linker (ld.so) and utilities +(ldconfig and ldd) for Linux. + +For those that were not involved in the development of ld.so, its main +feature is that the user-level, shared library and dynamic linking +support has been moved to its own, special shared library. This has +two significant advantages. First, the startup code for all binaries, +which must be linked statically, is reduced by about 2.5k. Second, +and probably more important, the shared library and dynamic linking +support can be upgraded for all binaries without having to relink by +simply installing a new ld.so. + +In addition to ld.so, this package also includes two, related +utilities, ldconfig and ldd. Ldconfig is used to automatically update +symbolic links to shared libraries and build the library cache used by +ld.so. This should hopefully put an end to the common problem of +accidentally deleting a critical library link (eg. /lib/libc.so.4). +Ldd is used to list the shared libraries dependencies for a binary. + +In order to use the debugging, library version of ld.so, the program +must be explcitly linked with the static libc.a. + +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. + +Both a.out and ELF versions of gcc, binutils and libc are currently +needed to recompile everything. If the ELF version is installed as +the default, set the value of GCC_DEFAULT to 'elf' in Config.mk, +otherwise, either leave it undefined or set it to a.out. Furthermore, +optimization level O2 or higher must be used to recompile ld-linux.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). + +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. + +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@ods.com diff --git a/gnu/libexec/ld.so/config.h b/gnu/libexec/ld.so/config.h new file mode 100644 index 00000000000..8d571be1e01 --- /dev/null +++ b/gnu/libexec/ld.so/config.h @@ -0,0 +1,46 @@ +#ifdef DEBUG +# define LDSO_IMAGE "../ld-so/ld.so" +# define LDSO_CONF "../util/ld.so.conf" +# define LDSO_CACHE "../util/ld.so.cache" +#else +# define LDSO_IMAGE "/lib/ld.so" +# define LDSO_CONF "/etc/ld.so.conf" +# define LDSO_CACHE "/var/run/ld.so.cache" +#endif + +#define LDD_ARGV0 "__LDD_ARGV0" +#define DIR_SEP ":, \t\n" +#define MAX_DIRS 32 + +#define VERSION "1.0" + +typedef void (*loadptr)(int func, ...); +typedef void (*callbackptr)(int ver, int nlibs, char **libs, + int nmods, char **mods); + +#define CALLBACK_VER 1 + +#define LIB_DLL 0 +#define LIB_ELF 1 + +#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; diff --git a/gnu/libexec/ld.so/ld.so/Makefile b/gnu/libexec/ld.so/ld.so/Makefile new file mode 100644 index 00000000000..3ea83da0769 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/Makefile @@ -0,0 +1,22 @@ +# $OpenBSD: Makefile,v 1.1 1996/09/18 08:15:23 pefo Exp $ + +SUBDIR= # libdl + +CFLAGS += -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER \ + -DUSE_CACHE -D__PIC__ -I${MACHINE_ARCH} + +SRCS= boot1.c hash.c readelflib1.c vsprintf.c elfinterp.c +PROG= ld.so +MAN= ld.so.8 +BINDIR=/usr/libexec + +.PATH: ${MACHINE_ARCH} + +ELF_LDFLAGS=--shared # using GNU ld + +$(PROG): + $(LD) -x -e _dl_boot $(ELF_LDFLAGS) -o $(DLINKER) $(OBJS) + + +.include +.include diff --git a/gnu/libexec/ld.so/ld.so/boot1.c b/gnu/libexec/ld.so/ld.so/boot1.c new file mode 100644 index 00000000000..9b2d78d50dc --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/boot1.c @@ -0,0 +1,848 @@ +/* Run an ELF binary on a linux system. + + Copyright (C) 1993-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. */ + + + +/* Program to load an ELF binary on a linux system, and run it. + * References to symbols in sharable libraries can be resolved by + * an ELF sharable 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. */ + +/* + * The main trick with this program is that initially, we ourselves are not + * dynamicly linked. This means that we cannot access any global variables + * since the GOT is initialized by the linker assuming a virtual address of 0, + * and we cannot call any functions since the PLT is not initialized at all + * (it will tend to want to call the dynamic linker + * + * There are further restrictions - we cannot use large switch statements, + * since the compiler generates tables of addresses and jumps through them. + * We can use inline functions, because these do not transfer control to + * a new address, but they must be static so that they are not exported + * from the modules. We cannot use normal syscall stubs, because these + * all reference the errno global variable which is not yet initialized. + * We can use all of the local stack variables that we want, since these + * are all referenced to %ebp or %esp. + * + * Life is further complicated by the fact that initially we do not want + * to do a complete dynamic linking. We want to allow the user to supply + * new functions replacing some of the library versions, and until we have + * the list of modules that we should search set up, we do not want to do + * any of this. Thus I have chosen to only perform the relocations for + * variables that start with "_dl_" since ANSI specifies that the user is + * not supposed to redefine any of these variables. + * + * Fortunately, the linker itself leaves a few clues lying around, and + * when the kernel starts the image, there are a few further clues. + * First of all, there is information buried on the stack that the kernel + * leaves, which includes information about the load address that the + * program interpreter was loaded at, the number of sections, the address + * the application was loaded at and so forth. Here this information + * is stored in the array dl_info, and the indicies are taken from the + * file /usr/include/sys/auxv.h on any SVr4 system. + * + * The linker itself leaves a pointer to the .dynamic section in the first + * slot of the GOT, and as it turns out, %ebx points to ghe GOT when + * you are using PIC code, so we just dereference this to get the address + * of the dynamic sections. + * + * Typically you must load all text pages as writable so that dynamic linking + * can succeed. The kernel under SVr4 loads these as R/O, so we must call + * mprotect to change the protections. Once we are done, we should set these + * back again, so the desired behavior is achieved. Under linux there is + * currently no mprotect function in the distribution kernel (although + * someone has alpha patches), so for now everything is loaded writable. + * + * We do not have access to malloc and friends at the initial stages of dynamic + * linking, and it would be handy to have some scratchpad memory available + * for use as we set things up. It is a bit of a kluge, but we mmap /dev/zero + * to get one page of scratchpad. A simpleminded _dl_malloc is provided so + * that we have some memory that can be used for this purpose. Typically + * we would not want to use the same memory pool as malloc anyway - the user + * might want to redefine malloc for example. + * + * Our first task is to perform a minimal linking so that we can call other + * portions of the dynamic linker. Once we have done this, we then build + * the list of modules that the application requires, using LD_LIBRARY_PATH + * if this is not a suid program (/usr/lib otherwise). Once this is done, + * we can do the dynamic linking as required (and we must omit the things + * we did to get the dynamic linker up and running in the first place. + * After we have done this, we just have a few housekeeping chores and we + * can transfer control to the user's application. + */ + +#include +#include +#include +#include +#include "hash.h" +#include + +#include "sysdep.h" +#include "syscall.h" +#include "string.h" + +static char * _dl_malloc_addr, *_dl_mmap_zero; +char * _dl_library_path = 0; /* Where we look for libraries */ +char *_dl_preload = 0; /* Things to be loaded before the libs. */ +char *_dl_progname = "/lib/ld.so.1"; +static char * _dl_not_lazy = 0; +static char * _dl_warn = 0; /* Used by ldd */ +static char * _dl_trace_loaded_objects = 0; +static int (*_dl_elf_main)(int, char **, char**); + +static int (*_dl_elf_init)(void); +extern void _dl_printhex(int); + +void * (*_dl_malloc_function)(int size) = NULL; + +struct r_debug * _dl_debug_addr = NULL; + +unsigned int * _dl_brkp; + +unsigned int * _dl_envp; + +#define DL_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) +/* + * Make sure that the malloc buffer is aligned on 4 byte boundary. For 64 bit + * platforms we may need to increase this to 8, but this is good enough for + * now. This is typically called after DL_MALLOC. + */ +#define REALIGN() malloc_buffer = (char *) (((unsigned int) malloc_buffer + 3) & ~(3)) + + + +#define ELF_HASH(RESULT,NAME) { \ + unsigned long hash = 0; \ + unsigned long tmp; \ + char * name = NAME; \ + while (*name){ \ + hash = (hash << 4) + *name++; \ + if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24; \ + hash &= ~tmp; \ + } \ + RESULT = hash; \ +} +extern _dl_runtime_resolve(void); +extern int _dl_interpreter_exit(int); +extern char * _dl_strdup(const char *); +extern char * _dl_getenv(char * symbol, char ** envp); +extern int _dl_fixup(struct elf_resolve * tpnt); + +extern Elf32_Dyn _DYNAMIC[]; +/* + * Datatype of a relocation on this platform + */ +#ifdef ELF_USES_RELOCA +typedef Elf32_Rela ELF_RELOC; +#else +typedef Elf32_Rel ELF_RELOC; +#endif + +/* + * This stub function is used by some debuggers. The idea is that they + * can set an internal breakpoint on it, so that we are notified when the + * address mapping is changed in some way. + */ +static void _dl_debug_state() +{ + return; +} + +void _dl_boot(void); + +void _dl_boot() +{ + unsigned int argc; + char ** argv, ** envp; + + unsigned int load_addr; + unsigned int *aux_dat; + int goof = 0; + unsigned int *stack; + struct elf_resolve * tpnt; + struct dyn_elf * rpnt; + struct elf_resolve * app_tpnt; + unsigned int brk_addr; + unsigned int dl_data[10]; + unsigned char * malloc_buffer, *mmap_zero; + int (*_dl_atexit)(void *); + int * lpnt; + Elf32_Dyn * dpnt; + unsigned int *hash_addr; + struct r_debug * debug_addr; + unsigned int *chains; + int indx; + + /* First obtain the information on the stack that tells us more about + what binary is loaded, where it is loaded, etc, etc */ + + + GET_ARGV(aux_dat, 0); + + stack = aux_dat; /* Remember this for start later */ + argc = *(aux_dat); + argv = (char **)(aux_dat + 1); + aux_dat += argc + 1; /* Skip over the argv pointers */ + aux_dat++; /* Skip over NULL at end of argv */ + envp = (char **) aux_dat; + while(*aux_dat) aux_dat++; /* Skip over the envp pointers */ + aux_dat++; /* Skip over NULL at end of envp */ + while(*aux_dat) + { + unsigned int * ad1; + ad1 = aux_dat + 1; + if( *aux_dat <= AT_ENTRY ) dl_data[*aux_dat] = *ad1; + aux_dat += 2; + } + + /* Next, locate the GOT */ + + load_addr = elf_machine_load_offset(); + + GET_GOT(got); + dpnt = (Elf32_Dyn *) ((int)_DYNAMIC + load_addr); + + /* OK, time for another hack. Now call mmap to get a page of writable + memory that can be used for a temporary malloc. We do not know brk + yet, so we cannot use real malloc. */ + + mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_COPY, -1, 0); + if(_dl_mmap_check_error(mmap_zero)) { + SEND_STDERR("dl_boot: mmap of zeros failed!\n"); + _dl_exit(13); + } + + tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset (tpnt, 0, sizeof (*tpnt)); + app_tpnt = DL_MALLOC(sizeof(struct elf_resolve)); + REALIGN(); + _dl_memset (app_tpnt, 0, sizeof (*app_tpnt)); + + /* + * This is used by gdb to locate the chain of shared libraries that are currently loaded. + */ + debug_addr = DL_MALLOC(sizeof(struct r_debug)); + REALIGN(); + _dl_memset (debug_addr, 0, sizeof (*debug_addr)); + + /* OK, that was easy. Next scan the DYNAMIC section of the image. + We are only doing ourself right now - we will have to do the rest later */ + + while(dpnt->d_tag != DT_NULL) { + if(dpnt->d_tag < DT_NUM) { + tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + } + else if(dpnt->d_tag >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) { + tpnt->dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val; + } + if(dpnt->d_tag == DT_TEXTREL) + tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + + { + Elf32_Phdr * ppnt; + int i; + + ppnt = (Elf32_Phdr *) dl_data[AT_PHDR]; + for(i=0; ip_type == PT_DYNAMIC) { + dpnt = (Elf32_Dyn *) ppnt->p_vaddr; + while(dpnt->d_tag != DT_NULL) + { + if(dpnt->d_tag < DT_NUM) { + app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + } + else if(dpnt->d_tag >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) { + app_tpnt->dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val; + } + /* + * We need to store the pointer to the debug data for the + * debugger in DYNAMIC if we find a DT_MIPS_RLD_MAP tag. The DYNAMIC + * area is write protected so we have to temporary remove + * the write protection. + */ + if(dpnt->d_tag == DT_MIPS_RLD_MAP) { + caddr_t addr; + addr = (caddr_t)((int)dpnt & ~(dl_data[AT_PAGESZ] - 1)); +#if 0 + _dl_mprotect(addr,dl_data[AT_PAGESZ],PROT_EXEC|PROT_READ|PROT_WRITE); +#endif + *(struct r_debug **)(dpnt->d_un.d_val) = debug_addr; +#if 0 + _dl_mprotect(addr,dl_data[AT_PAGESZ],PROT_EXEC|PROT_READ); +#endif + } + if(dpnt->d_tag == DT_TEXTREL) + app_tpnt->dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + } + } + + /* Get some more of the information that we will need to dynamicly link + this module to itself */ + + hash_addr = (unsigned int *) (tpnt->dynamic_info[DT_HASH]+load_addr); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + chains = hash_addr; + + /* OK, now do the relocations. We do not do a lazy binding here, so + that once we are done, we have considerably more flexibility. */ + + goof = 0; + for(indx=0; indx < 2; indx++) + { + int i; + ELF_RELOC * rpnt; + unsigned int * reloc_addr; + unsigned int symbol_addr; + int symtab_index; + unsigned int rel_addr, rel_size; + + + rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]); + rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]); + + + if(!rel_addr) continue; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) (rel_addr + load_addr); + for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){ + Elf32_Sym * symtab; + char * strtab; + reloc_addr = (int *) (load_addr + (int)rpnt->r_offset); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr); + if(symtab_index) { + + /* We only do a partial dynamic linking right now. The user + is not supposed to redefine any symbols that start with + a '_', so we can do this with confidence. */ + + symbol_addr = load_addr + symtab[symtab_index].st_value; + + if(!symbol_addr) { + /* + * This will segfault - you cannot call a function until + * we have finished the relocations. + */ + SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol "); + SEND_STDERR(strtab + symtab[symtab_index].st_name); + SEND_STDERR(" undefined.\n"); + goof++; + } + } + /* + * Use this machine-specific macro to perform the actual relocation. + */ + PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, &symtab[symtab_index], load_addr); + } + } + + if (goof) _dl_exit(14); + + /* OK, at this point we have a crude malloc capability. Start to build + the tables of the modules that are required for this beast to run. + We start with the basic executable, and then go from there. Eventually + we will run across ourself, and we will need to properly deal with that + as well. */ + + _dl_malloc_addr = malloc_buffer; + + _dl_mmap_zero = mmap_zero; +/* tpnt = _dl_malloc(sizeof(struct elf_resolve)); */ + +/* Now we have done the mandatory linking of some things. We are now + free to start using global variables, since these things have all been + fixed up by now. Still no function calls outside of this library , + since the dynamic resolver is not yet ready. */ + + lpnt = (int *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr); + lpnt[0] = (int)_dl_runtime_resolve; + if(lpnt[1] & 0x80000000) + lpnt[1] = (Elf32_Addr) ((unsigned) tpnt | 0x80000000); + + /* OK, this was a big step, now we need to scan all of the user images + and load them properly. */ + + tpnt->next = 0; + tpnt->libname = 0; + tpnt->libtype = program_interpreter; + + { Elf32_Ehdr * epnt; + Elf32_Phdr * ppnt; + int i; + + epnt = (Elf32_Ehdr *) dl_data[AT_BASE]; + tpnt->n_phent = epnt->e_phnum; + tpnt->ppnt = ppnt = (Elf32_Phdr *) ((int)epnt + epnt->e_phoff); + for(i=0;i < epnt->e_phnum; i++, ppnt++){ + if(ppnt->p_type == PT_DYNAMIC) { + tpnt->dynamic_addr = ppnt->p_vaddr + load_addr; + tpnt->dynamic_size = ppnt->p_filesz; + } + } + } + + tpnt->chains = chains; + tpnt->loadaddr = (char *) load_addr; + tpnt->loadoffs = (char *) 0; + + brk_addr = 0; + rpnt = NULL; + + /* At this point we are now free to examine the user application, + and figure out which libraries are supposed to be called. Until + we have this list, we will not be completely ready for dynamic linking */ + + { + Elf32_Phdr * ppnt; + int i; + + ppnt = (Elf32_Phdr *) dl_data[AT_PHDR]; + for(i=0; ip_type == PT_LOAD) { + if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr) + brk_addr = ppnt->p_vaddr + ppnt->p_memsz; + } + if(ppnt->p_type == PT_DYNAMIC) { + /* make sure it's really there. */ + if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue; + /* OK, we have what we need - slip this one into the list. */ + app_tpnt = _dl_add_elf_hash_table("", 0, 0, + app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz); + _dl_loaded_modules->libtype = elf_executable; + _dl_loaded_modules->ppnt = (Elf32_Phdr *) dl_data[AT_PHDR]; + _dl_loaded_modules->n_phent = dl_data[AT_PHNUM]; + _dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt, 0, sizeof (*rpnt)); + rpnt->dyn = _dl_loaded_modules; + app_tpnt->usage_count++; + app_tpnt->symbol_scope = _dl_symbol_tables; + lpnt = (int *) (app_tpnt->dynamic_info[DT_PLTGOT]); + lpnt[0] = (int)_dl_runtime_resolve; + if(lpnt[1] & 0x80000000) + lpnt[1] = (Elf32_Addr) ((unsigned) app_tpnt | 0x80000000); + } + if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have + this before */ + tpnt->libname = _dl_strdup((char *) ppnt->p_vaddr); + } + } + } + + if (argv[0]) + _dl_progname = argv[0]; + + /* Now we need to figure out what kind of options are selected. + Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */ + { + _dl_not_lazy = _dl_getenv("LD_BIND_NOW",envp); + +#ifndef IBCS_COMPATIBLE + _dl_preload = _dl_getenv("LD_ELF_PRELOAD", envp); + if (!_dl_preload) +#endif + _dl_preload = _dl_getenv("LD_PRELOAD", envp); +#ifndef IBCS_COMPATIBLE + _dl_library_path = _dl_getenv("LD_ELF_LIBRARY_PATH", envp); + if (!_dl_library_path) +#endif + _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp); + + if(!_dl_suid_ok() ) { + if (_dl_preload) { + *_dl_preload = '\0'; + _dl_preload = 0; + } + if (_dl_library_path) { + *_dl_library_path = '\0'; + _dl_library_path = 0; + } + } + } + + _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp); + + + /* OK, we now have the application in the list, and we have some + basic stuff in place. Now search through the list for other shared + libraries that should be loaded, and insert them on the list in the + correct order. */ + +#ifdef USE_CACHE + _dl_map_cache(); +#endif + + { + struct elf_resolve *tcurr; + struct elf_resolve * tpnt1; + char * lpnt; + + tcurr = _dl_loaded_modules; + if (_dl_preload) { + int i; + char *str; + char c=1; + str = _dl_preload; + for (i = 0; c != 0; i++) { + if (_dl_preload[i] == ':' || _dl_preload[i] == '\0') { + c= _dl_preload[i]; + _dl_preload[i]=0; + tpnt1 = _dl_load_shared_library(_dl_symbol_tables, str); + if (!tpnt1) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", str); + else + { + _dl_fdprintf(2, "%s: can't load library '%s'\n", + _dl_progname,str); + _dl_exit(15); + } + } + else + { + if (_dl_trace_loaded_objects && !tpnt1->usage_count) + _dl_fdprintf(1, "\t%s => %s\n", str, tpnt1->libname); + rpnt->next = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + str=_dl_preload+i+1; + _dl_preload[i]=c; + } + } + } + do{ + for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) + { + if(dpnt->d_tag == DT_NEEDED) + { + lpnt = tcurr->loadoffs + tcurr->dynamic_info[DT_STRTAB] + + dpnt->d_un.d_val; + if(tpnt && _dl_strcmp(lpnt, tpnt->libname) == 0) { + struct elf_resolve * ttmp; + ttmp = _dl_loaded_modules; + while(ttmp->next) ttmp = ttmp->next; + ttmp->next = tpnt; + tpnt->prev = ttmp; + tpnt->next = NULL; + rpnt->next = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); + rpnt = rpnt->next; + rpnt->dyn = tpnt; + tpnt->usage_count++; + tpnt->symbol_scope = _dl_symbol_tables; + tpnt = NULL; + continue; + } + if(!(tpnt1 = _dl_load_shared_library(_dl_symbol_tables, lpnt))) { + if (_dl_trace_loaded_objects) + _dl_fdprintf(1, "\t%s => not found\n", lpnt); + else + { + _dl_fdprintf(2, "%s: can't load library '%s'\n", + _dl_progname, lpnt); + _dl_exit(16); + } + } + else + { + if (_dl_trace_loaded_objects && !tpnt1->usage_count) + _dl_fdprintf(1, "\t%s => %s\n", lpnt, tpnt1->libname); + rpnt->next = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); + rpnt = rpnt->next; + tpnt1->usage_count++; + tpnt1->symbol_scope = _dl_symbol_tables; + tpnt1->libtype = elf_lib; + rpnt->dyn = tpnt1; + } + } + } + + tcurr = tcurr->next; + } while(tcurr); + } + +#ifdef USE_CACHE + _dl_unmap_cache(); +#endif + + /* ldd uses uses this. I am not sure how you pick up the other flags */ + if(_dl_trace_loaded_objects) + { + _dl_warn = _dl_getenv("LD_WARN", envp); + if(!_dl_warn) _dl_exit(0); + } + + /* + * If the program interpreter is not in the module chain, add it. This will + * be required for dlopen to be able to access the internal functions in the + * dynamic linker. + */ + if(tpnt) { + struct elf_resolve * tcurr; + + tcurr = _dl_loaded_modules; + if (tcurr) + while(tcurr->next) tcurr = tcurr->next; + tpnt->next = NULL; + tpnt->usage_count++; + + if (tcurr) { + tcurr->next = tpnt; + tpnt->prev = tcurr; + } + else { + _dl_loaded_modules = tpnt; + tpnt->prev = NULL; + } + if (rpnt) { + rpnt->next = + (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt->next, 0, sizeof (*(rpnt->next))); + rpnt = rpnt->next; + } else { + rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); + _dl_memset (rpnt, 0, sizeof (*(rpnt->next))); + } + rpnt->dyn = tpnt; + tpnt = NULL; + } + + /* + * OK, now all of the kids are tucked into bed in their proper addresses. + * Now we go through and look for REL and RELA records that indicate fixups + * to the GOT tables. We need to do this in reverse order so that COPY + * directives work correctly */ + + + goof = _dl_fixup(_dl_loaded_modules); + + if(goof || _dl_trace_loaded_objects) _dl_exit(0); + + /* OK, at this point things are pretty much ready to run. Now we + need to touch up a few items that are required, and then + we can let the user application have at it. Note that + the dynamic linker itself is not guaranteed to be fully + dynamicly linked if we are using ld.so.1, so we have to look + up each symbol individually. */ + + + _dl_brkp = (unsigned int *) _dl_find_hash("___brk_addr", NULL, 1, NULL, 0); + if (_dl_brkp) *_dl_brkp = brk_addr; + + _dl_envp = (unsigned int *) _dl_find_hash("__environ", NULL, 1, NULL, 0); + + if (_dl_envp) *_dl_envp = (unsigned int) envp; + + _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0); + + for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) + { + /* Apparently crt1 for the application is responsible for handling this. + * We only need to run the init/fini for shared libraries + */ + if (tpnt->libtype == program_interpreter || + 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)(); + } + if(_dl_atexit && tpnt->dynamic_info[DT_FINI]) + { + (*_dl_atexit)(tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]); + } +#undef DL_DEBUG +#ifdef DL_DEBUG + else + { + _dl_fdprintf(2, tpnt->libname); + _dl_fdprintf(2, ": "); + if (!_dl_atexit) + _dl_fdprintf(2, "The address is atexit () is 0x0."); + if (!tpnt->dynamic_info[DT_FINI]) + _dl_fdprintf(2, "Invalid .fini section."); + _dl_fdprintf(2, "\n"); + } +#endif +#undef DL_DEBUG + } + + /* + * OK, fix one more thing - set up the debug_addr structure to point + * to our chain. Later we may need to fill in more fields, but this + * should be enough for now. + */ + debug_addr->r_map = (struct link_map *) _dl_loaded_modules; + debug_addr->r_version = 1; + debug_addr->r_ldbase = load_addr; + debug_addr->r_brk = (unsigned long) &_dl_debug_state; + _dl_debug_addr = debug_addr; + + /* OK we are done here. Turn out the lights, and lock up. */ + _dl_elf_main = (int (*)(int, char**, char**)) dl_data[AT_ENTRY]; + + /* + * Transfer control to the application. + */ + START(); +} + + +int _dl_fixup(struct elf_resolve * tpnt) +{ + int goof = 0; + if(tpnt->next) goof += _dl_fixup(tpnt->next); + + if(tpnt->dynamic_info[DT_REL]) { + 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); + } + if(tpnt->dynamic_info[DT_RELA]) { + _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname); + _dl_exit(18); + } + if(tpnt->dynamic_info[DT_JMPREL]) + { + if (tpnt->init_flag & JMP_RELOCS_DONE) return goof; + tpnt->init_flag |= JMP_RELOCS_DONE; + + if(! _dl_not_lazy || *_dl_not_lazy == 0) + goof += _dl_parse_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], 1); + } + + elf_machine_got_rel(tpnt); + + return goof; +} + +void * _dl_malloc(int size) { + void * retval; + + if(_dl_malloc_function) + return (*_dl_malloc_function)(size); + + if(_dl_malloc_addr-_dl_mmap_zero+size>4096) { + _dl_mmap_zero = _dl_malloc_addr = (unsigned char *) _dl_mmap((void*) 0, size, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_COPY, -1, 0); + if(_dl_mmap_check_error(_dl_mmap_zero)) { + _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname); + _dl_exit(20); + } + } + retval = _dl_malloc_addr; + _dl_malloc_addr += size; + + /* + * Align memory to 4 byte boundary. Some platforms require this, others + * simply get better performance. + */ + _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); + return retval; +} + +char * _dl_getenv(char * symbol, char ** envp) +{ + char * pnt; + char * pnt1; + while ((pnt = *envp++)) { + pnt1 = symbol; + while(*pnt && *pnt1 && *pnt == *pnt1) {pnt1++; pnt++;} + if(!*pnt || *pnt != '=' || *pnt1) continue; + return pnt+1; + } + return 0; +} + +char * _dl_strdup(const char * string){ + void * retval; + char * pnt; + + pnt = retval = _dl_malloc_addr; + while(*string) + *pnt++ = *string++; + *pnt++ = 0; + _dl_malloc_addr = pnt; + /* + * Align memory to 4 byte boundary. Some platforms require this, others + * simply get better performance. + */ + _dl_malloc_addr = (char *) (((unsigned int) _dl_malloc_addr + 3) & ~(3)); + return retval; +} + +/* In principle we could do the .fini stuff here, but we already + registered this stuff with atexit */ +int _dl_interpreter_exit(int exitcode){ +/* _dl_fdprintf(2, "Hey, look where I am!\n"); */ + return 0; +} + +void _dl_printhex(no) +{ +static char xc[]="0123456789abcdef"; + + int i; + + _dl_write(1, " 0x", 3); + for(i=0; i < 8; i++) { + _dl_write(1, &xc[((no >> 28) & 0xf)], 1); + no <<= 4; + } +} + diff --git a/gnu/libexec/ld.so/ld.so/hash.c b/gnu/libexec/ld.so/ld.so/hash.c new file mode 100644 index 00000000000..a7f9a1b9fa5 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/hash.c @@ -0,0 +1,225 @@ +/* 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. */ + + + +/* Various symbol table handling functions, including symbol lookup */ + +#include +#include +#include +#include + +#include "hash.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 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; + tpnt = _dl_loaded_modules; + while(tpnt){ + if(_dl_strcmp(tpnt->libname, libname) == 0) return tpnt; + tpnt = tpnt->next; + }; + 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, + char * loadoffs, + 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] + loadoffs); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + tpnt->chains = hash_addr; + } + tpnt->loadaddr = loadaddr; + tpnt->loadoffs = loadoffs; + for(i=0; i<(DT_NUM + DT_MDEP); 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; + char * strtab; + Elf32_Sym * symtab; + unsigned int elf_hash_number, hn; + char * weak_result; + struct elf_resolve * first_def; + struct dyn_elf * rpnt, first; + + 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); + } + + 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 ) + { + return weak_result; + } + + /* + * Avoid calling .urem here. + */ + do_rem(hn, elf_hash_number, tpnt->nbucket); + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadoffs); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadoffs); + /* + * 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(!first_def) first_def = tpnt; + if(f_tpnt && first_def == f_tpnt && symtab[si].st_shndx == 0) + continue; + + switch(ELF32_ST_BIND(symtab[si].st_info)){ + case STB_GLOBAL: + return tpnt->loadoffs + symtab[si].st_value; + case STB_WEAK: + if (!weak_result) weak_result = tpnt->loadoffs + symtab[si].st_value; + break; + default: /* Do local symbols need to be examined? */ + break; + } + } + } + } + return weak_result; +} + + diff --git a/gnu/libexec/ld.so/ld.so/hash.h b/gnu/libexec/ld.so/ld.so/hash.h new file mode 100644 index 00000000000..fea594091b5 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/hash.h @@ -0,0 +1,100 @@ + +struct dyn_elf{ + struct elf_resolve * dyn; + struct dyn_elf * next_handle; /* Used by dlopen et al. */ + struct dyn_elf * next; +}; + +#include + +#define DT_MDEP (DT_MIPS_HIPAGENO - DT_LOPROC + 1) + +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. */ + char * loadoffs; + 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[DT_NUM + DT_MDEP]; + + unsigned int dynamic_size; + unsigned int n_phent; + Elf32_Phdr * ppnt; +}; + +#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 elf_resolve * _dl_check_hashed_files(char * libname); +extern struct elf_resolve * _dl_add_elf_hash_table(char * libname, + char * loadaddr, + char * loadoffs, + 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 struct elf_resolve * _dl_load_shared_library(struct dyn_elf *, + char * libname); +int _dl_copy_fixups(struct dyn_elf * tpnt); + + +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_write(int, const char *, int); +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 + diff --git a/gnu/libexec/ld.so/ld.so/i386/Makefile b/gnu/libexec/ld.so/ld.so/i386/Makefile new file mode 100644 index 00000000000..6f5ba5685db --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/i386/Makefile @@ -0,0 +1,49 @@ +include ../../Version.mk +include ../../Config.mk + +CC = $(ELFCC) +AS = $(ELFAS) +LD = $(ELFLD) + +CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER +CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops + +../%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ +../%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +SRC1S = resolve.S +SRC2S = elfinterp.c + +SRCS = $(SRC1S) $(SRC2S) +OBJ1S = $(SRC1S:.S=.o) +OBJ2S = $(SRC2S:.c=.o) +OBJS = $(OBJ1S) $(OBJ2S) + +DLINK_OBJS:= $(addprefix ../, $(OBJS)) + +lib:: $(DLINK_OBJS) + +obj: $(DLINK_OBJS) + +asm: $(ASMS) + +realclean:: + $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~ + +clean:: + $(RM) -f core *.o *.a *.s *.i tmp_make *~ + +depend:: + $(CC) $(CFLAGS) -M $(SRCS) | \ + sed -e 's,^[ ]*\(.*\.o\)[ ]*:,../\1:,' > .depend +# $(MAKE) subdir TARGET=depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gnu/libexec/ld.so/ld.so/i386/elfinterp.c b/gnu/libexec/ld.so/ld.so/i386/elfinterp.c new file mode 100644 index 00000000000..5db1b46a780 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/i386/elfinterp.c @@ -0,0 +1,328 @@ +/* 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 +#include +#include +#include +#ifdef IBCS_COMPATIBLE +#include +#else +#include +#endif +#include +#include + +#include "hash.h" +#include "linuxelf.h" +#include "syscall.h" +#include "string.h" + +#define SVR4_COMPATIBILITY + +extern char *_dl_progname; + +extern _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 */ + +#ifndef BROKEN_LINKER +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++; + }; + }; + _dl_memcpy((char *) symtab[symtab_index].st_value, + (char *) symbol_addr, + symtab[symtab_index].st_size); + }; + return goof; +} +#endif + + diff --git a/gnu/libexec/ld.so/ld.so/i386/resolve.S b/gnu/libexec/ld.so/ld.so/i386/resolve.S new file mode 100644 index 00000000000..7236cd70d4c --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/i386/resolve.S @@ -0,0 +1,51 @@ +#if 0 +#include +#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: +#ifdef __PIC__ + pushl %ebx; + call .L26 +.L24: + movl RESOLVER@GOT(%ebx),%ebx + call *%ebx +#else + call RESOLVER +#endif + popl %ebx + addl $8,%esp + jmp *%eax +#ifdef __PIC__ +.L26: + popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx + jmp .L24 +#endif +.LFE2: + .size RESOLVE,.LFE2-RESOLVE diff --git a/gnu/libexec/ld.so/ld.so/i386/string.h b/gnu/libexec/ld.so/ld.so/i386/string.h new file mode 100644 index 00000000000..f5b3402295b --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/i386/string.h @@ -0,0 +1,439 @@ +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include /* for size_t */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern inline char * _dl_strcpy(char * dest,const char *src); +extern inline char * _dl_strncpy(char * dest,const char *src,size_t count); +extern inline char * _dl_strcat(char * dest,const char * src); +extern inline char * _dl_strncat(char * dest,const char * src,size_t count); +extern inline int _dl_strcmp(const char * cs,const char * ct); +extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count); +extern inline char * _dl_strchr(const char * s,char c); +extern inline char * _dl_strrchr(const char * s,char c); +extern inline size_t _dl_strspn(const char * cs, const char * ct); +extern inline size_t _dl_strcspn(const char * cs, const char * ct); +extern inline char * _dl_strpbrk(const char * cs,const char * ct); +extern inline char * _dl_strstr(const char * cs,const char * ct); +extern inline size_t _dl_strlen(const char * s); +extern inline char * _dl_strtok(char * s,const char * ct); +extern inline void * _dl_memcpy(void * to, const void * from, size_t n); +extern inline void * _dl_memmove(void * dest,const void * src, size_t n); +extern inline int _dl_memcmp(const void * cs,const void * ct,size_t count); +extern inline void * _dl_memchr(const void * cs,char c,size_t count); +extern inline void * _dl_memset(void * s,char c,size_t count); + +/* + * This string-include defines all string functions as inline + * functions. Use gcc. It also assumes ds=es=data space, this should be + * normal. Most of the string-functions are rather heavily hand-optimized, + * see especially strtok,strstr,str[c]spn. They should work, but are not + * very easy to understand. Everything is done entirely within the register + * set, making the functions fast and clean. String instructions have been + * used through-out, making for "slightly" unclear code :-) + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +extern inline char * _dl_strcpy(char * dest,const char *src) +{ +__asm__("cld\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : /* no output */ + :"S" (src),"D" (dest):"si","di","ax","memory"); +return dest; +} + +extern inline char * _dl_strncpy(char * dest,const char *src,size_t count) +{ +__asm__("cld\n" + "1:\tdecl %2\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "rep\n\t" + "stosb\n" + "2:" + : /* no output */ + :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory"); +return dest; +} + +extern inline char * _dl_strcat(char * dest,const char * src) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : /* no output */ + :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx"); +return dest; +} + +extern inline char * _dl_strncat(char * dest,const char * src,size_t count) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n\t" + "movl %4,%3\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %2,%2\n\t" + "stosb" + : /* no output */ + :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count) + :"si","di","ax","cx","memory"); +return dest; +} + +extern inline int _dl_strcmp(const char * cs,const char * ct) +{ +register int __res; +__asm__("cld\n" + "5:\tlodsb\n\t" + "scasb\n\t" + "jne 6f\n\t" + "testb %%al,%%al\n\t" + "jne 5b\n\t" + "xorl %%eax,%%eax\n\t" + "jmp 7f\n" + "6:\tmovl $1,%%eax\n\t" + "jb 7f\n\t" + "negl %%eax\n" + "7:" + :"=a" (__res):"D" (cs),"S" (ct):"si","di"); +return __res; +} + +extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count) +{ +register int __res; +__asm__("cld\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "scasb\n\t" + "jne 3f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %%eax,%%eax\n\t" + "jmp 4f\n" + "3:\tmovl $1,%%eax\n\t" + "jb 4f\n\t" + "negl %%eax\n" + "4:" + :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx"); +return __res; +} + +extern inline char * _dl_strchr(const char * s,char c) +{ +register char * __res; +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "je 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "movl $1,%1\n" + "2:\tmovl %1,%0\n\t" + "decl %0" + :"=a" (__res):"S" (s),"0" (c):"si"); +return __res; +} + +extern inline char * _dl_strrchr(const char * s,char c) +{ +register char * __res; +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "jne 2f\n\t" + "movl %%esi,%0\n\t" + "decl %0\n" + "2:\ttestb %%al,%%al\n\t" + "jne 1b" + :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si"); +return __res; +} + +extern inline size_t _dl_strspn(const char * cs, const char * ct) +{ +register char * __res; +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res-cs; +} + +extern inline size_t _dl_strcspn(const char * cs, const char * ct) +{ +register char * __res; +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res-cs; +} + +extern inline char * _dl_strpbrk(const char * cs,const char * ct) +{ +register char * __res; +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n\t" + "decl %0\n\t" + "jmp 3f\n" + "2:\txorl %0,%0\n" + "3:" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res; +} + +extern inline char * _dl_strstr(const char * cs,const char * ct) +{ +register char * __res; +__asm__("cld\n\t" \ + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %4,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct) + :"cx","dx","di","si"); +return __res; +} + +extern inline size_t _dl_strlen(const char * s) +{ +register int __res; +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di"); +return __res; +} + +extern char * ___strtok; + +extern inline char * _dl_strtok(char * s,const char * ct) +{ +register char * __res; +__asm__("testl %1,%1\n\t" + "jne 1f\n\t" + "testl %0,%0\n\t" + "je 8f\n\t" + "movl %0,%1\n" + "1:\txorl %0,%0\n\t" + "movl $-1,%%ecx\n\t" + "xorl %%eax,%%eax\n\t" + "cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "je 7f\n\t" /* empty delimeter-string */ + "movl %%ecx,%%edx\n" + "2:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 7f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 2b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 7f\n\t" + "movl %1,%0\n" + "3:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 5f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 3b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 5f\n\t" + "movb $0,(%1)\n\t" + "incl %1\n\t" + "jmp 6f\n" + "5:\txorl %1,%1\n" + "6:\tcmpb $0,(%0)\n\t" + "jne 7f\n\t" + "xorl %0,%0\n" + "7:\ttestl %0,%0\n\t" + "jne 8f\n\t" + "movl %0,%1\n" + "8:" + :"=b" (__res),"=S" (___strtok) + :"0" (___strtok),"1" (s),"g" (ct) + :"ax","cx","dx","di","memory"); +return __res; +} + +extern inline void * _dl_memcpy(void * to, const void * from, size_t n) +{ +__asm__("cld\n\t" + "movl %%edx, %%ecx\n\t" + "shrl $2,%%ecx\n\t" + "rep ; movsl\n\t" + "testb $1,%%dl\n\t" + "je 1f\n\t" + "movsb\n" + "1:\ttestb $2,%%dl\n\t" + "je 2f\n\t" + "movsw\n" + "2:\n" + : /* no output */ + :"d" (n),"D" ((long) to),"S" ((long) from) + : "cx","di","si","memory"); +return (to); +} + +extern inline void * _dl_memmove(void * dest,const void * src, size_t n) +{ +if (dest= -_dl_MAX_ERRNO) +extern inline int _dl_open(char * addr, unsigned int flags); +extern inline int _dl_write(int fd, const char * buf, int len); +extern inline int _dl_read(int fd, const char * buf, int len); +extern inline int _dl_mprotect(const char * addr, int size, int prot); +#include +extern inline int _dl_stat(char * filename, struct stat *st); +extern inline int _dl_munmap(char * addr, int size); + +/* Here are the definitions for a bunch of syscalls that are required + 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. */ + +extern inline volatile void _dl_exit(int status) +{ + int __res; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %0\n\tpushl $0\n\tmovl %1,%%eax\n\t" \ + "lcall $7,$0" : : "r" (status), "a" (__IBCS_exit)); +#else + __asm__ volatile ("movl %%ecx,%%ebx\n"\ + "int $0x80" \ + : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status))); +#endif +} + +extern inline volatile void _dl_close(int fd) +{ + int status; + +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %1\n\t" \ + "pushl $0\n\t" \ + "movl %2,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+4\n\t" \ + "xor %%eax, %%eax\n\t" \ + "addl $8,%%esp\n\t" \ + : "=a" (status) : "r" (fd), "a" (__IBCS_close)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%ecx,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_close),"c" ((long)(fd))); + +#endif +} + +extern inline int _dl_mmap(void * addr, unsigned int size, + unsigned int prot, + unsigned int flags, int fd, + unsigned int f_offset) +{ + int malloc_buffer; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %7\n\t" \ + "pushl %6\n\t" \ + "pushl %5\n\t" \ + "pushl %4\n\t" \ + "pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+4\n\t" \ + "xor %%eax, %%eax\n\t" \ + "addl $28,%%esp\n\t" \ + : "=a" (malloc_buffer) : "a" (__IBCS_mmap), + "rm" (addr), "rm" (size), "rm" (prot), "rm" (flags), + "rm" (fd), "rm" (f_offset)); +#else + __asm__ volatile ("pushl %%ebx\n\t" \ + "pushl %7\n\t" \ + "pushl %6\n\t" \ + "pushl %5\n\t" \ + "pushl %4\n\t" \ + "pushl %3\n\t" \ + "pushl %2\n\t" \ + "movl %%esp,%%ebx\n\t" \ + "int $0x80\n\t" \ + "addl $24,%%esp\n\t" \ + "popl %%ebx\n" \ + : "=a" (malloc_buffer) : "a" (__NR_mmap), + "rm" (addr), "rm" (size), "rm" (prot), "rm" (flags), + "rm" (fd), "rm" (f_offset)); +#endif + return malloc_buffer; +} + + +extern inline int _dl_open(char * addr, unsigned int flags) +{ + int zfileno; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+7\n\t" \ + "movl $-1, %%eax\n\t" \ + "addl $12,%%esp\n\t" \ + :"=a" (zfileno) : "i" (__IBCS_open), "rm" (addr), "rm" (flags)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (zfileno) \ + : "0" (__NR_open),"S" ((long)(addr)),"c" ((long)(flags))); +#endif + + return zfileno; +} + +extern inline int _dl_write(int fd, const char * buf, int len) +{ + int status; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %4\n\t" \ + "pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+4\n\t" \ + "xor %%eax, %%eax\n\t" \ + "addl $12,%%esp\n\t" \ + :"=a" (status) : "i" (__IBCS_write), "rm" (fd), "rm" (buf), "rm" (len)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); +#endif +} + + +extern inline int _dl_read(int fd, const char * buf, int len) +{ + int status; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %4\n\t" \ + "pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+4\n\t" \ + "xor %%eax, %%eax\n\t" \ + "addl $12,%%esp\n\t" \ + : "=a" (status) : "i" (__IBCS_read), "rm" (fd), "rm" (buf), "rm" (len)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_read),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); +#endif +} + +extern inline int _dl_mprotect(const char * addr, int size, int prot) +{ + int status; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %4\n\t" \ + "pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+7\n\t" \ + "movl $-1, %%eax\n\t" \ + "addl $16,%%esp\n\t" \ + :"=a" (status) : "i" (__IBCS_mprotect), "rm" (addr), "rm" (size), "rm" (prot)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_mprotect),"S" ((long)(addr)),"c" ((long)(size)),"d" ((long)(prot))); +#endif + return status; +} + +extern inline int _dl_stat(char * filename, struct stat *st) +{ + int ret; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+7\n\t" \ + "movl $-1, %%eax\n\t" \ + "addl $12,%%esp\n\t" \ + :"=a" (ret) : "i" (__IBCS_stat), "rm" (filename), "rm" (st)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (ret) \ + : "0" (__NR_stat),"S" (filename),"c" (st)); +#endif + + return ret; +} + +extern inline int _dl_munmap(char * addr, int size) +{ + int ret; +#ifdef IBCS_COMPATIBLE + __asm__ volatile ("pushl %3\n\t" \ + "pushl %2\n\t" \ + "pushl $0\n\t" \ + "movl %1,%%eax\n\t" \ + "lcall $7,$0\n\t" \ + "jnb .+7\n\t" \ + "movl $-1, %%eax\n\t" \ + "addl $12,%%esp\n\t" \ + :"=a" (ret) : "i" (__IBCS_munmap), "rm" (addr), "rm" (size)); +#else + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (ret) \ + : "0" (__NR_munmap),"S" ((long)(addr)),"c" ((long)(size))); +#endif + + return ret; +} + +/* + * 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) +{ + unsigned int uid, euid, gid, egid; + euid = egid = 0; /* So compiler does not warn us */ + +#ifdef IBCS_COMPATIBLE + __asm__("movl %2,%%eax\n\tlcall $7,$0" :"=a" (uid), "=d" (euid) :"a" (__IBCS_getuid)); + __asm__("movl %2,%%eax\n\tlcall $7,$0" :"=a" (gid), "=d" (egid) :"a" (__IBCS_getgid)); +#else + __asm__ volatile ("int $0x80" : "=a" (uid) : "0" (__NR_getuid)); + __asm__ volatile ("int $0x80" : "=a" (euid) : "0" (__NR_geteuid)); + __asm__ volatile ("int $0x80" : "=a" (gid) : "0" (__NR_getgid)); + __asm__ volatile ("int $0x80" : "=a" (egid) : "0" (__NR_getegid)); +#endif + + if(uid == euid && gid == egid) + return 1; + else + return 0; +} + diff --git a/gnu/libexec/ld.so/ld.so/i386/sysdep.h b/gnu/libexec/ld.so/ld.so/i386/sysdep.h new file mode 100644 index 00000000000..09eeb4ba6bc --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/i386/sysdep.h @@ -0,0 +1,90 @@ + +/* + * 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 this because we do not want to call .udiv in the library. + */ +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +#define do_rem(result, n, base) result = (n % base) diff --git a/gnu/libexec/ld.so/ld.so/ld.so.8 b/gnu/libexec/ld.so/ld.so/ld.so.8 new file mode 100644 index 00000000000..19bd5633458 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/ld.so.8 @@ -0,0 +1,172 @@ +.TH ld.so 8 "30 March 1995" +.SH NAME +ld.so \- a.out dynamic linker/loader +.SH DESCRIPTION +.B ld.so +completes the final process of linking all necessary references to +sharable objects and unreferenced symbols in an impure executable, +(usually a +.I dynamically +.I linked +.IR executable ), +to produce a runnable file. +.PP +Unless explicitly specified via the +.B \-static +option to +.B ld +during compilation, all Linux binaries in a.out format will be "incomplete" +and require further linking at run time. +.BR ld.so 's +job is thus to complete the linking process started at compilation. +.PP +The necessary dynamically linked libraries (DLL's) which the executable +requires to complete it's linking process are searched for in the following +order +.IP o +Using the environment variable +.BR LD_AOUT_LIBRARY_PATH . +Except if the executable is a setuid/setgid binary, in which case it +is ignored. +.IP o +Using the environment variable +.BR LD_LIBRARY_PATH . +Except if +.B LD_AOUT_LIBRARY_PATH +is specified or 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 MESSAGES +The following, possibly fatal, warnings may be output by +.B ld.so +.TP +.SB can't find library 'libfoo' +If +.B ld.so +cannot find the library the executable requires anywhere. +.TP +.SB can't load library 'libfoo' +If the library is corrupt. +.TP +.SB incompatible library 'libfoo' +.PD 0 +.TP +.SB Require major version x and found y +.PD +.B ld.so +cannot use the library version found as it is incompatable with the +binary attempting to be executed. +.TP +.SB using incompatible library 'libfoo' +.PD 0 +.TP +.SB Desire minor version >= x and found y +.PD +Even though the minor version is incompatable +.B ld.so +will attempt to use it. +This message is suppressed if the environment variable +.B LD_NOWARN +is set. +.TP +.SB too many directories in library path +There is a hard coded limit of 32 search directories. The above warning will +ensue it this limit is exceeded. +.TP +.SB dynamic linker error in fixup pass 1,2 +.PD 0 +.TP +.SB dynamic linker error in resolve pass +.TP +.SB dynamic linker error in reset pass +.PD +An attempt to perform necessary fixups and or relocations failed. These are +usually fatal and signifies possible binary corruption. +.TP +.SB can't map cache file '/etc/ld.so.cache' +.PD 0 +.TP +.SB cache file '/etc/ld.so.cache' is corrupt +.TP +.SB cache file '/etc/ld.so.cache' has wrong version +.TP +.SB cache file '/etc/ld.so.cache' is empty +.PD +A problem was encountered with the cache. +Execution will continue as if the cache did not exist. +.SH ENVIRONMENT +.TP +.B LD_AOUT_LIBRARY_PATH +A colon-separated list of directories in which to search for +libraries at execution-time. +Similar to the +.B PATH +environment variable. +.TP +.B LD_LIBRARY_PATH +A colon-separated list of directories in which to search for +libraries at execution-time if +.B LD_AOUT_LIBRARY_PATH +is not specified. +Similar to the +.B PATH +environment variable. +.TP +.B LD_NOWARN +Suppress warnings about libraries with incompatible minor version numbers. +.TP +.B LD_KEEPDIR +Don't ignore the directory in the names of libraries to be loaded. +Use of this option is strongly discouraged. +.TP +.B LD_AOUT_PRELOAD +The name of an additional, user-specified, shared library to be loaded +after all others. +This can be used to selectively override functions in other shared libraries. +.B LD_PRELOAD +The name of an additional, user-specified, shared library to be loaded +after all others if +.B LD_AOUT_PRELOAD +is not specified. +This can be used to selectively override functions in other shared libraries. +.SH FILES +.PD 0 +.TP 20 +.B /lib/ld.so +execution time 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 lib*.so.version +shared libraries +.TP +.B lib*.sa +exported initialized library data. +.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 compatable or newer version of +libraries. +.PP +.B ld.so +functionality is only available for executables compiled using libc version +4.4.3 or greater. +.SH AUTHORS +David Engel, Eric Youngdale, Peter MacDonald, Hongjiu Lu, Linus +Torvalds, Lars Wirzenius and Mitch D'Souza (not necessarily in that order). diff --git a/gnu/libexec/ld.so/ld.so/m68k/Makefile b/gnu/libexec/ld.so/ld.so/m68k/Makefile new file mode 100644 index 00000000000..6f5ba5685db --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/Makefile @@ -0,0 +1,49 @@ +include ../../Version.mk +include ../../Config.mk + +CC = $(ELFCC) +AS = $(ELFAS) +LD = $(ELFLD) + +CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER +CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops + +../%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ +../%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +SRC1S = resolve.S +SRC2S = elfinterp.c + +SRCS = $(SRC1S) $(SRC2S) +OBJ1S = $(SRC1S:.S=.o) +OBJ2S = $(SRC2S:.c=.o) +OBJS = $(OBJ1S) $(OBJ2S) + +DLINK_OBJS:= $(addprefix ../, $(OBJS)) + +lib:: $(DLINK_OBJS) + +obj: $(DLINK_OBJS) + +asm: $(ASMS) + +realclean:: + $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~ + +clean:: + $(RM) -f core *.o *.a *.s *.i tmp_make *~ + +depend:: + $(CC) $(CFLAGS) -M $(SRCS) | \ + sed -e 's,^[ ]*\(.*\.o\)[ ]*:,../\1:,' > .depend +# $(MAKE) subdir TARGET=depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gnu/libexec/ld.so/ld.so/m68k/elfinterp.c b/gnu/libexec/ld.so/ld.so/m68k/elfinterp.c new file mode 100644 index 00000000000..e41174bc0c8 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/elfinterp.c @@ -0,0 +1,360 @@ +/* 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 +#include +#include +#include +#ifdef IBCS_COMPATIBLE +#include +#else +#include +#endif +#include +#include + +#include "hash.h" +#include "linuxelf.h" +#include "syscall.h" +#include "sysdep.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 + rpnt->r_addend; + break; + case R_68K_RELATIVE: + *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend; + 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. */ + +#ifndef BROKEN_LINKER +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++; + } + } + _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr, + symtab[symtab_index].st_size); + } + return goof; +} +#endif diff --git a/gnu/libexec/ld.so/ld.so/m68k/resolve.S b/gnu/libexec/ld.so/ld.so/m68k/resolve.S new file mode 100644 index 00000000000..7d0be194031 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/resolve.S @@ -0,0 +1,29 @@ +#if 0 +#include +#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 + jsr __dl_linux_resolver +#endif + moveml %sp@+,%a0/%a1 + addql #8,%sp + jmp @(%d0) +.LFE2: + .size __dl_linux_resolve,.LFE2-__dl_linux_resolve diff --git a/gnu/libexec/ld.so/ld.so/m68k/string.h b/gnu/libexec/ld.so/ld.so/m68k/string.h new file mode 100644 index 00000000000..526772122fb --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/string.h @@ -0,0 +1,303 @@ +#ifndef _DL_STRING_H_ +#define _DL_STRING_H_ + +#include /* for size_t */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern inline char *_dl_strcpy (char *dest, const char *src); +extern inline char *_dl_strncpy (char *dest, const char *src, size_t count); +extern inline char *_dl_strcat (char *dest, const char *src); +extern inline char *_dl_strncat (char *dest, const char *src, size_t count); +extern inline int _dl_strcmp (const char *cs, const char *ct); +extern inline int _dl_strncmp (const char *cs, const char *ct, size_t count); +extern inline char *_dl_strchr (const char *s, int c); +extern inline char *_dl_strrchr (const char *s, int c); +extern inline size_t _dl_strspn (const char *cs, const char *ct); +extern inline size_t _dl_strcspn (const char *cs, const char *ct); +extern inline char *_dl_strpbrk (const char *cs, const char *ct); +extern inline char *_dl_strstr (const char *cs, const char *ct); +extern inline size_t _dl_strlen (const char *s); +extern inline char *_dl_strtok (char *s, const char *ct); +extern inline void *_dl_memcpy (void *to, const void *from, size_t n); +extern inline void *_dl_memmove (void *dest, const void *src, size_t n); +extern inline int _dl_memcmp (const void *cs, const void *ct, size_t count); +extern inline void *_dl_memchr (const void *cs, int c, size_t count); +extern inline void *_dl_memset (void *s, int c, size_t count); + +/* Make sure we are using our inline version. */ +#define strlen(s) _dl_strlen(s) + +extern inline char * +_dl_strcpy (char *dest, const char *src) +{ + char *xdest = dest; + + while ((*dest++ = *src++) != '\0') + ; + return xdest; +} + +extern inline char * +_dl_strncpy (char *dest, const char *src, size_t n) +{ + char *xdest = dest; + + if (n == 0) + return xdest; + + while ((*dest = *src++) != '\0') + if (--n == 0) + break; + return xdest; +} + +extern inline char * +_dl_strcat (char *dest, const char *src) +{ + char *xdest = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return xdest; +} + +extern inline char * +_dl_strncat (char *dest, const char *src, size_t count) +{ + char *xdest = dest; + + if (count) + { + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + if (--count == 0) + break; + } + + return xdest; +} + +extern inline int +_dl_strcmp (const char *cs, const char *ct) +{ + char c; + + while ((c = *cs++) == *ct++) + if (c == 0) + return 0; + return c - *--ct; +} + +extern inline int +_dl_strncmp (const char *cs, const char *ct, size_t count) +{ + char c; + + if (!count) + return 0; + + while ((c = *cs++) == *ct++) + if (c == 0 || --count == 0) + return 0; + return c - *--ct; +} + +extern inline char * +_dl_strchr (const char *s, int c) +{ + const char ch = c; + + for (; *s != ch; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} + +extern inline char * +_dl_strrchr (const char * s, int c) +{ + char *res = NULL; + const char ch = c; + + for (;; ++s) + { + if (*s == ch) + res = (char *) s; + if (*s == '\0') + break; + } + return res; +} + +extern inline size_t +_dl_strspn (const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + ++count; + } + + return count; +} + +extern inline size_t +_dl_strcspn (const char *s, const char *reject) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = reject; *a != '\0'; ++a) + if (*p == *a) + return count; + ++count; + } + + return count; +} + +extern inline char * +_dl_strpbrk (const char *cs, const char *ct) +{ + const char *sc1, *sc2; + + for (sc1 = cs; *sc1 != '\0'; ++sc1) + for (sc2 = ct; *sc2 != '\0'; ++sc2) + if (*sc1 == *sc2) + return (char *) sc1; + return NULL; +} + +extern inline char * +_dl_strstr (const char *cs, const char *ct) +{ + const char *p; + + for (;; cs++) + { + for (p = ct; *p == *cs; p++, cs++) + if (*p == 0) + return (char *) cs - (p - ct); + cs -= p - ct; + if (*cs == 0) + return NULL; + } +} + +extern inline size_t +_dl_strlen (const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + ; + return sc - s; +} + +extern char * ___strtok; + +extern inline char * +_dl_strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) + return NULL; + sbegin += _dl_strspn (sbegin, ct); + if (*sbegin == '\0') + { + ___strtok = NULL; + return NULL; + } + send = _dl_strpbrk (sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return sbegin; +} + +extern inline void * +_dl_memcpy (void *to, const void *from, size_t n) +{ + char *cto = to; + const char *cfrom = from; + + while (n--) + *cto++ = *cfrom++; + return to; +} + +extern inline void * +_dl_memmove (void *dest, const void *src, size_t n) +{ + char *cdest = dest; + const char *csrc = src; + + if (dest < src) + { + while (n--) + *cdest++ = *csrc++; + } + else + { + cdest += n; + csrc += n; + while (n--) + *--cdest = *--csrc; + } + return dest; +} + +extern inline int +_dl_memcmp (const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + + for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--) + if (*su1 != *su2) + return *su1 < *su2 ? -1 : 1; + return 0; +} + +extern inline void * +_dl_memchr (const void *cs, int c, size_t count) +{ + const unsigned char ch = c; + const unsigned char *s = cs; + + for (; count != 0; ++s, count--) + if (*s == ch) + return (void *) s; + return NULL; +} + +extern inline void * +_dl_memset (void *s, int c, size_t count) +{ + char *cs = s; + + while (count--) + *cs++ = c; + return s; +} + +#endif diff --git a/gnu/libexec/ld.so/ld.so/m68k/syscall.h b/gnu/libexec/ld.so/ld.so/m68k/syscall.h new file mode 100644 index 00000000000..c5f15e37b4b --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/syscall.h @@ -0,0 +1,182 @@ +#ifdef USE_CACHE +#include +#endif + +extern inline void _dl_exit (int status) __attribute__ ((noreturn)); +extern inline int _dl_close (int fd); +extern inline int _dl_mmap (void *addr, unsigned int size, + unsigned int prot, + unsigned int flags, int fd, + unsigned int f_offset); +#ifndef _dl_MAX_ERRNO +#define _dl_MAX_ERRNO 4096 +#endif +#define _dl_mmap_check_error(__res) \ + ((int) __res < 0 && (int) __res >= -_dl_MAX_ERRNO) +extern inline int _dl_open (const char *addr, unsigned int flags); +extern inline int _dl_write (int fd, const char *buf, int len); +extern inline int _dl_read (int fd, char *buf, int len); +extern inline int _dl_mprotect (const void *addr, int size, int prot); +#ifdef USE_CACHE +extern inline int _dl_stat (const char *, struct stat *); +extern inline int _dl_munmap (const void *, unsigned int); +#endif + +/* Here are the definitions for a bunch of syscalls that are required + 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. */ + +extern inline void +_dl_exit (int status) +{ + register int __res __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n" + "trap #0" + : "=d" (__res) + : "0" (__NR_exit), "d" (status) + : "%d0", "%d1"); + for (;;); +} + +extern inline int +_dl_close (int fd) +{ + register int status __asm__ ("%d0"); + + __asm__ volatile ("movel %2,%/d1\n" + "trap #0" + : "=d" (status) + : "0" (__NR_close), "d" (fd) + : "%d0", "%d1"); + return status; +} + +extern inline int +_dl_mmap (void *addr, unsigned int size, unsigned int prot, + unsigned int flags, int fd, unsigned int f_offset) +{ + register int malloc_buffer __asm__ ("%d0"); + 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) f_offset; + + __asm__ volatile ("movel %2,%/d1\n\t" + "trap #0" + : "=d" (malloc_buffer) + : "0" (__NR_mmap), "g" (buffer) + : "%d0", "%d1"); + return malloc_buffer; +} + + +extern inline int +_dl_open (const char *addr, unsigned int flags) +{ + register int zfileno __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "trap #0" + : "=d" (zfileno) + : "0" (__NR_open), "g" (addr), "g" (flags) + : "%d0", "%d1", "%d2"); + return zfileno; +} + +extern inline int +_dl_write (int fd, const char* buf, int len) +{ + register int status __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "movel %4,%/d3\n\t" + "trap #0" + : "=d" (status) + : "0" (__NR_write), "g" (fd), "g" (buf), "g" (len) + : "%d0", "%d1", "%d2", "%d3"); + return status; +} + + +extern inline int +_dl_read (int fd, char *buf, int len) +{ + register int status __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "movel %4,%/d3\n\t" + "trap #0" + : "=d" (status) + : "0" (__NR_read), "g" (fd), "g" (buf), "g" (len) + : "%d0", "%d1", "%d2", "%d3"); + return status; +} + +extern inline int +_dl_mprotect (const void *addr, int size, int prot) +{ + register int status __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "movel %4,%/d3\n\t" + "trap #0" + : "=d" (status) + : "0" (__NR_mprotect), "g" (addr), "g" (size), "g" (prot) + : "%d0", "%d1", "%d2", "%d3"); + return status; +} + +#ifdef USE_CACHE +extern inline int +_dl_stat (const char *name, struct stat *sb) +{ + register int status __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "trap #0" + : "=d" (status) + : "0" (__NR_stat), "g" (name), "g" (sb) + : "%d0", "%d1", "%d2"); + return status; +} + +extern inline int +_dl_munmap (const void *addr, unsigned int size) +{ + register int status __asm__ ("%d0"); + __asm__ volatile ("movel %2,%/d1\n\t" + "movel %3,%/d2\n\t" + "trap #0" + : "=d" (status) + : "0" (__NR_munmap), "g" (addr), "g" (size) + : "%d0", "%d1"); + return status; +} +#endif + +/* 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) +{ + unsigned int uid, euid, gid, egid; + + __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0" + : "=g" (uid) : "i" (__NR_getuid) : "%d0"); + __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0" + : "=g" (euid) : "i" (__NR_geteuid) : "%d0"); + __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0" + : "=g" (gid) : "i" (__NR_getgid) : "%d0"); + __asm__ volatile ("movel %1,%%d0; trap #0; movel %%d0,%0" + : "=g" (egid) : "i" (__NR_getegid) : "%d0"); + + return (uid == euid && gid == egid); +} diff --git a/gnu/libexec/ld.so/ld.so/m68k/sysdep.h b/gnu/libexec/ld.so/ld.so/m68k/sysdep.h new file mode 100644 index 00000000000..b69bab27842 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/m68k/sysdep.h @@ -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) + (RELP)->r_addend; \ + break; \ + case R_68K_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. */ + +#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)) diff --git a/gnu/libexec/ld.so/ld.so/mips/Makefile b/gnu/libexec/ld.so/ld.so/mips/Makefile new file mode 100644 index 00000000000..b46abb0c7c8 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/Makefile @@ -0,0 +1,49 @@ +.include "../../Version.mk" +.include "../../Config.mk" + +CC = $(ELFCC) +AS = $(ELFAS) +LD = $(ELFLD) + +CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER +CFLAGS += -mabicalls -G0 -fPIC -D__PIC__ #-DDEBUG # -funroll-loops + +../%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ +../%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +SRC1S = resolve.S +SRC2S = elfinterp.c + +SRCS = $(SRC1S) $(SRC2S) +OBJ1S = $(SRC1S:.S=.o) +OBJ2S = $(SRC2S:.c=.o) +OBJS = $(OBJ1S) $(OBJ2S) + +DLINK_OBJS:= $(addprefix ../, $(OBJS)) + +lib:: $(DLINK_OBJS) + +obj: $(DLINK_OBJS) + +asm: $(ASMS) + +realclean:: + $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~ + +clean:: + $(RM) -f core *.o *.a *.s *.i tmp_make *~ + +depend:: + $(CC) $(CFLAGS) -M $(SRCS) | \ + sed -e 's,^[ ]*\(.*\.o\)[ ]*:,../\1:,' > .depend +# $(MAKE) subdir TARGET=depend + +# +# include a dependency file if one exists +# +#ifeq (.depend,$(wildcard .depend)) +#include .depend +#endif + diff --git a/gnu/libexec/ld.so/ld.so/mips/elf-machine.h b/gnu/libexec/ld.so/ld.so/mips/elf-machine.h new file mode 100644 index 00000000000..b44b64dc8f3 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/elf-machine.h @@ -0,0 +1,27 @@ +/* This file defines MIPS specific ELF types, structures, and macros. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _ELF_MIPS_H +#define _ELF_MIPS_H 1 + +#define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM) +#define DT_PROCNUM (DT_MIPS_HIPAGENO - DT_LOPROC + 1) + + +#endif diff --git a/gnu/libexec/ld.so/ld.so/mips/elf.h b/gnu/libexec/ld.so/ld.so/mips/elf.h new file mode 100644 index 00000000000..03c151933cd --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/elf.h @@ -0,0 +1,610 @@ +/* This file defines standard ELF types, structures, and macros. +Copyright (C) 1995 Free Software Foundation, Inc. +Contributed by Ian Lance Taylor (ian@cygnus.com). + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _ELF_H +#define _ELF_H 1 + + +/* Standard ELF types. + + Using __attribute__ mode ensures that gcc will choose the right for + these types. */ + +typedef unsigned int Elf32_Addr __attribute__ ((mode (SI))); +typedef unsigned int Elf32_Half __attribute__ ((mode (HI))); +typedef unsigned int Elf32_Off __attribute__ ((mode (SI))); +typedef int Elf32_Sword __attribute__ ((mode (SI))); +typedef unsigned int Elf32_Word __attribute__ ((mode (SI))); + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_PAD 7 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types. */ +#define ET_LOPROC 0xff00 /* Processor-specific */ +#define ET_HIPROC 0xffff /* Processor-specific */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_486 6 /* Intel 80486 */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* Amdahl */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ + +#define EM_PARISC 15 /* HPPA */ + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_NUM 12 /* Number of defined types. */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf32_Half st_shndx; /* Section index */ +} Elf32_Sym; + +/* Special section index. */ + +#define SHN_UNDEF 0 /* No section, undefined symbol. */ + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_NUM 5 /* Number of defined types. */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +/* Program segment header. */ + +typedef struct { + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_NUM 7 /* Number of defined types. */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \ + (((X) & PF_W) ? PROT_WRITE : 0) | \ + (((X) & PF_X) ? PROT_EXEC : 0)) + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_NUM 24 /* Number used. */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Standard 64 bit ELF types. */ + +typedef unsigned int Elf64_Addr __attribute__ ((mode (DI))); +typedef unsigned int Elf64_Half __attribute__ ((mode (HI))); +typedef unsigned int Elf64_Off __attribute__ ((mode (DI))); +typedef int Elf64_Sword __attribute__ ((mode (SI))); +typedef int Elf64_Sxword __attribute__ ((mode (DI))); +typedef unsigned int Elf64_Word __attribute__ ((mode (SI))); +typedef unsigned int Elf64_Xword __attribute__ ((mode (DI))); +typedef unsigned int Elf64_Byte __attribute__ ((mode (QI))); +typedef unsigned int Elf64_Section __attribute__ ((mode (HI))); + +/* 64 bit ELF file header. */ + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* 64 bit section header. */ + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* 64 bit symbol table entry. */ + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + Elf64_Byte st_info; /* Symbol type and binding */ + Elf64_Byte st_other; /* No defined meaning, 0 */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The 64 bit st_info field is the same as the 32 bit one. */ + +#define ELF64_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF64_ST_TYPE(val) ((val) & 0xf) +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + int a_type; /* Entry type */ + union + { + long a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (); /* Function pointer value */ + } a_un; +} Elf32_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#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 */ + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ + +/* SUN SPARC specific definitions. */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information */ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of debug map pointer */ + +/* Legal values for DT_MIPS_FLAG Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +/* Legal values for l_flags. */ + +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +#endif /* elf.h */ diff --git a/gnu/libexec/ld.so/ld.so/mips/elf_abi.h b/gnu/libexec/ld.so/ld.so/mips/elf_abi.h new file mode 100644 index 00000000000..89a992a7fff --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/elf_abi.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 1995 Erik Theisen + * 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _ELF_ABI_H_ +#define _ELF_ABI_H_ + +#include + +/* + * These typedefs needs to be handled better - + * doesn't work on 64-bit machines. Note: + * there currently isn't a 64-bit ABI. + */ +typedef u_int32_t Elf32_Addr; /* Unsigned program address */ +typedef u_int32_t Elf32_Off; /* Unsigned file offset */ +typedef int32_t Elf32_Sword; /* Signed large integer */ +typedef u_int32_t Elf32_Word; /* Unsigned large integer */ +typedef u_int16_t Elf32_Half; /* Unsigned medium integer */ + +/* e_ident[] identification indexes */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_PAD 7 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASS32 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct elfhdr{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 - unused? */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +/* + * Don't know if EM_MIPS_RS4_BE, + * EM_SPARC64, EM_PARISC, + * or EM_PPC are ABI compliant + */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */ +#define EM_PARISC 15 /* HPPA */ +#define EM_PPC 20 /* PowerPC */ +#define EM_NUM 13 /* number of machine types */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct { + Elf32_Word sh_name; /* name - index into section header + string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_NUM 12 /* number of section types */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific section attributes */ + +/* Symbol Table Entry */ +typedef struct elf32_sym { + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_NUM 5 /* number of symbol types */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char) (i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +/* Program Header */ +typedef struct { + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_NUM 7 /* Number of segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ + + +#if 0 +#error No ELF RTLD support yet +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union + { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +extern Elf32_Dyn _DYNAMIC[]; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library + /* search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ +#endif + + +#endif /* _ELF_ABI_H_ */ + diff --git a/gnu/libexec/ld.so/ld.so/mips/elfinterp.c b/gnu/libexec/ld.so/ld.so/mips/elfinterp.c new file mode 100644 index 00000000000..de1507e1945 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/elfinterp.c @@ -0,0 +1,449 @@ +/* Run an ELF binary on a OpenBSD 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. */ + + +/* Program to load an ELF binary on a OpenBSD 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 +#include +#include +#include +#include +#include +#include + +#include "hash.h" +#include "syscall.h" +#include "sysdep.h" +#include "string.h" + +extern char *_dl_progname; + +/* Search loaded objects' symbol tables for a definition of + the symbol UNDEF_NAME. If NOSELF is nonzero, then *REF + cannot satisfy the reference itself; some different binding + must be found. */ + +Elf32_Addr +_dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref, + struct elf_resolve *symbol_scope, + const char *reference_name, + int noself) +{ + unsigned long int hash = _dl_elf_hash (undef_name); + struct elf_resolve *map; + struct + { + Elf32_Addr a; + const Elf32_Sym *s; + } weak_value = { 0, NULL }; + + /* Search the relevant loaded objects for a definition. */ + for (map = symbol_scope; map; map = map->next) + { + const Elf32_Sym *symtab; + const char *strtab; + Elf32_Word symidx; + + symtab = ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]); + strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]); + + /* Search the appropriate hash bucket in this object's symbol table + for a definition for the same symbol name. */ + for (symidx = map->elf_buckets[hash % map->nbucket]; + symidx != STN_UNDEF; + symidx = map->chains[symidx]) + { + const Elf32_Sym *sym = &symtab[symidx]; + + if (sym->st_value == 0 || /* No value. */ + sym->st_shndx == SHN_UNDEF || /* PLT entry. */ + (noself && sym == *ref)) /* The reference can't define it. */ + continue; + + switch (ELF32_ST_TYPE (sym->st_info)) + { + case STT_NOTYPE: + case STT_FUNC: + case STT_OBJECT: + break; + default: + /* Not a code/data definition. */ + continue; + } + + if (sym != *ref && _dl_strcmp (strtab + sym->st_name, undef_name)) + /* Not the symbol we are looking for. */ + continue; + + switch (ELF32_ST_BIND (sym->st_info)) + { + case STB_GLOBAL: + /* Global definition. Just what we need. */ + *ref = sym; + return (Elf32_Word)map->loadoffs; + case STB_WEAK: + /* Weak definition. Use this value if we don't find another. */ + if (! weak_value.s) + { + weak_value.s = sym; + weak_value.a = (Elf32_Word)map->loadoffs; + } + break; + default: + /* Local symbols are ignored. */ + break; + } + } + } + + if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK) { + _dl_fdprintf(2,"%s: undefined symbol: '%s' %x\n", _dl_progname, undef_name,(*ref)->st_info); + } + + *ref = weak_value.s; + return weak_value.a; +} + + +/* Get link_map for this object. */ +static struct elf_resolve * +elf_machine_runtime_link_map (Elf32_Addr gpreg) +{ + struct elf_resolve *l = 0; + Elf32_Addr *got = (Elf32_Addr *) (gpreg - 0x7ff0); + Elf32_Word g1; + + g1 = ((Elf32_Word *) got)[1]; + + if (g1 & 0x80000000) + l = (void *) (g1 & ~0x80000000); +#if 0 + else + l = LOOK_UP_A_TABLE (got); +#endif + return l; +} + +/* This function is called from assembler function _dl_runtime_resolve + which converts special argument registers t7 ($15) and t8 ($24): + t7 address to return to the caller of the function + t8 index for this function symbol in .dynsym + to usual c arguments. */ + +Elf32_Addr +__dl_runtime_resolve (Elf32_Word sym_index, + Elf32_Word return_address, + Elf32_Addr old_gpreg, + Elf32_Addr stub_return_address) +{ + struct elf_resolve *l = elf_machine_runtime_link_map (old_gpreg); + + const Elf32_Sym *const symtab + = (const Elf32_Sym *) (l->loadoffs + l->dynamic_info[DT_SYMTAB]); + char *strtab + = (void *) (l->loadoffs + l->dynamic_info[DT_STRTAB]); + Elf32_Addr *got + = (Elf32_Addr *) (l->loadoffs + l->dynamic_info[DT_PLTGOT]); + + const Elf32_Word local_gotno + = (const Elf32_Word) l->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM]; + const Elf32_Word gotsym + = (const Elf32_Word) l->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]; + + const Elf32_Sym *definer; + Elf32_Addr loadbase; + Elf32_Addr funcaddr; + struct elf_resolve *scope, *real_next; + + /* Look up the symbol's run-time value. */ + + real_next = l->next; + if (l->dynamic_info[DT_SYMBOLIC]) + { + l->next = _dl_loaded_modules; + if (l->prev) + l->prev->next = real_next; + scope = l; + } + else + scope = _dl_loaded_modules; + + definer = &symtab[sym_index]; + loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, + scope, l->libname, 0); + + + /* Restore list frobnication done above for DT_SYMBOLIC. */ + l->next = real_next; + if (l->prev) + l->prev->next = l; + + /* Apply the relocation with that value. */ + funcaddr = loadbase + definer->st_value; + *(got + local_gotno + sym_index - gotsym) = funcaddr; + + return funcaddr; +} + +asm ("\n\ + .text\n\ + .align 2\n\ + .globl _dl_runtime_resolve\n\ + .type _dl_runtime_resolve,@function\n\ + .ent _dl_runtime_resolve\n\ +_dl_runtime_resolve:\n\ + .set noreorder\n\ + # Save old GP to $3.\n\ + move $3,$28\n\ + # Modify t9 ($25) so as to point .cpload instruction.\n\ + addu $25,8\n\ + # Compute GP.\n\ + .cpload $25\n\ + .set reorder\n\ + # Save arguments and sp value in stack.\n\ + subu $29, 40\n\ + .cprestore 32\n\ + sw $15, 36($29)\n\ + sw $4, 12($29)\n\ + sw $5, 16($29)\n\ + sw $6, 20($29)\n\ + sw $7, 24($29)\n\ + sw $16, 28($29)\n\ + move $16, $29\n\ + move $4, $24\n\ + move $5, $15\n\ + move $6, $3\n\ + move $7, $31\n\ + jal __dl_runtime_resolve\n\ + move $29, $16\n\ + lw $31, 36($29)\n\ + lw $4, 12($29)\n\ + lw $5, 16($29)\n\ + lw $6, 20($29)\n\ + lw $7, 24($29)\n\ + lw $16, 28($29)\n\ + addu $29, 40\n\ + move $25, $2\n\ + jr $25\n\ + .end _dl_runtime_resolve\n\ +"); + + +int +_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr, + int rel_size, int lazy) +{ + int i; + char *strtab; + int reloc_type; + int goof = 0; + Elf32_Sym *symtab; + const Elf32_Sym *symbol; + const Elf32_Sym *ref; + Elf32_Rel *rpnt; + unsigned int *reloc_addr; + unsigned int symbol_addr; + int symtab_index; + struct elf_resolve *real_next, *scope; + + /* Now parse the relocation information */ + + rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadoffs); + rel_size = rel_size / sizeof (Elf32_Rel); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadoffs); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadoffs); + + /* Set scope. */ + real_next = tpnt->next; + if (tpnt->dynamic_info[DT_SYMBOLIC]) { + if (tpnt->prev) + tpnt->prev->next = real_next; + tpnt->next = _dl_loaded_modules; + scope = tpnt; + } + else + scope = _dl_loaded_modules; + + for (i = 0; i < rel_size; i++, rpnt++) { + reloc_addr = (int *) (tpnt->loadoffs + (int) rpnt->r_offset); + reloc_type = ELF32_R_TYPE (rpnt->r_info); + symtab_index = ELF32_R_SYM (rpnt->r_info); + symbol = symtab + symtab_index; + symbol_addr = (unsigned int) tpnt->loadoffs; + ref = symbol; + + if (tpnt->libtype == program_interpreter + && (!symtab_index || _dl_symbol (strtab + symbol->st_name))) + continue; + + if (symtab_index == 0xffffff) + continue; + + if (symtab_index && + !(ELF32_ST_BIND (ref->st_info) == STB_LOCAL && + ELF32_ST_TYPE (ref->st_info) == STT_NOTYPE)) { + + symbol_addr = (unsigned int) + _dl_lookup_symbol (strtab + symbol->st_name, &ref, + scope, tpnt->libname, 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 (!ref && ELF32_ST_BIND (symbol->st_info) == STB_GLOBAL) { + _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symbol->st_name); + goof++; + } + } + switch (reloc_type) + { + case R_MIPS_NONE: + break; + + case R_MIPS_REL32: + if (ELF32_ST_BIND (symbol->st_info) == STB_LOCAL + && (ELF32_ST_TYPE (symbol->st_info) == STT_SECTION + || ELF32_ST_TYPE (symbol->st_info) == STT_NOTYPE)) { + *reloc_addr += (unsigned int) tpnt->loadoffs; + } + else { + *reloc_addr += ref ? symbol_addr + ref->st_value : 0; + } + break; + + default: + _dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname); + if (symtab_index) + _dl_fdprintf (2, "'%s'", strtab + symbol->st_name); + _dl_fdprintf (2, "\n"); + _dl_exit (1); + } + + } + /* Restore list frobnication done above for DT_SYMBOLIC. */ + tpnt->next = real_next; + if (tpnt->prev) + tpnt->prev->next = tpnt; + + return goof; +} + +/* Relocate GOT. */ +void +elf_machine_got_rel (struct elf_resolve *map) +{ + Elf32_Addr *got; + Elf32_Sym *sym = 0; + int i, n; + struct elf_resolve *real_next, *scope; + char *strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]); + + Elf32_Addr resolve (const Elf32_Sym *sym) + { + const Elf32_Sym *ref; + Elf32_Addr sym_addr; + + sym_addr = _dl_lookup_symbol (strtab + sym->st_name, &ref, scope, + map->libname, 1); + if(ref) + return sym_addr + ref->st_value; + else + return 0; + } + + got = (Elf32_Addr *) ((void *) map->loadoffs + map->dynamic_info[DT_PLTGOT]); + + /* Add the run-time display to all local got entries. */ + i = (got[1] & 0x80000000)? 2: 1; + n = map->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM]; + while (i < n) { + got[i++] += (Elf32_Addr)map->loadoffs; + } + + /* Set scope. */ + real_next = map->next; + if (map->dynamic_info[DT_SYMBOLIC]) { + if (map->prev) + map->prev->next = real_next; + map->next = _dl_loaded_modules; + scope = map; + } + else + scope = _dl_loaded_modules; + + /* Handle global got entries. */ + got += n; + sym = (Elf32_Sym *) ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]); + sym += map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]; + i = (map->dynamic_info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM] + - map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]); + + while (i--) { + if (sym->st_shndx == SHN_UNDEF) { + if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC) { +#if 0 /*XXX*/ + if (sym->st_value /* && maybe_stub (sym->st_value) */) { + *got = sym->st_value + (Elf32_Word)map->loadoffs; + } + else { + *got = resolve (sym); + } +#else + *got = resolve (sym); +#endif + } + else /* if (*got == 0 || *got == QS) */ { + *got = resolve (sym); + } + } + else if (sym->st_shndx == SHN_COMMON) { + *got = resolve (sym); + } + else if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC + /* && maybe_stub (*got) */) { + *got += (Elf32_Word)map->loadoffs; + } + else { + *got = sym->st_value + (Elf32_Word)map->loadoffs; + } + + got++; + sym++; + } + + /* Restore list frobnication done above for DT_SYMBOLIC. */ + map->next = real_next; + if (map->prev) + map->prev->next = map; + + return; +} diff --git a/gnu/libexec/ld.so/ld.so/mips/link.h b/gnu/libexec/ld.so/ld.so/mips/link.h new file mode 100644 index 00000000000..2ce104856ee --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/link.h @@ -0,0 +1,247 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _LINK_H +#define _LINK_H 1 + +#include +#include + + +/* Rendezvous structure used by the run-time dynamic linker to communicate + details of shared object loading to the debugger. If the executable's + dynamic section has a DT_MIPS_RLD_MAP element, the run-time linker sets + that element's value to the address where this structure can be found. */ + +struct r_debug + { + int r_version; /* Version number for this protocol. */ + + struct link_map *r_map; /* Head of the chain of loaded objects. */ + + /* This is the address of a function internal to the run-time linker, + that will always be called when the linker begins to map in a + library or unmap it, and again when the mapping change is complete. + The debugger can set a breakpoint at this address if it wants to + notice shared object mapping changes. */ + Elf32_Addr r_brk; + enum + { + /* This state value describes the mapping change taking place when + the `r_brk' address is called. */ + RT_CONSISTENT, /* Mapping change is complete. */ + RT_ADD, /* Beginning to add a new object. */ + RT_DELETE, /* Beginning to remove an object mapping. */ + } r_state; + + Elf32_Addr r_ldbase; /* Base address the linker is loaded at. */ + }; + +/* This symbol refers to the "dynamic structure" in the `.dynamic' section + of whatever module refers to `_DYNAMIC'. So, to find its own + `struct r_debug', a program could do: + for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL) + if (dyn->d_tag == DT_MIPS_RLD_MAP) r_debug = (struct r_debug) dyn->d_un.d_ptr; + */ + +extern Elf32_Dyn _DYNAMIC[]; + + +/* Structure describing a loaded shared object. The `l_next' and `l_prev' + members form a chain of all the shared objects loaded at startup. + + These data structures exist in space used by the run-time dynamic linker; + modifying them may have disastrous results. */ + +struct link_map + { + /* These first few members are part of the protocol with the debugger. + This is the same format used in SVR4. */ + + Elf32_Addr l_addr; /* Base address shared object is loaded at. */ + char *l_name; /* Absolute file name object was found in. */ + Elf32_Dyn *l_ld; /* Dynamic section of the shared object. */ + struct link_map *l_next, *l_prev; /* Chain of loaded objects. */ + + /* All following members are internal to the dynamic linker. + They may change without notice. */ + + const char *l_libname; /* Name requested (before search). */ + + /* Indexed pointers to dynamic section. */ + Elf32_Dyn *l_info[DT_NUM + DT_PROCNUM]; + + const Elf32_Phdr *l_phdr; /* Pointer to program header table in core. */ + Elf32_Word l_phnum; /* Number of program header entries. */ + Elf32_Addr l_entry; /* Entry point location. */ + + /* Symbol hash table. */ + Elf32_Word l_nbuckets; + const Elf32_Word *l_buckets, *l_chain; + + unsigned int l_opencount; /* Reference count for dlopen/dlclose. */ + enum /* Where this object came from. */ + { + lt_executable, /* The main executable program. */ + lt_interpreter, /* The interpreter: the dynamic linker. */ + lt_library, /* Library needed by main executable. */ + lt_loaded, /* Extra run-time loaded shared object. */ + } l_type:2; + unsigned int l_deps_loaded:1; /* Nonzero if DT_NEEDED items loaded. */ + unsigned int l_relocated:1; /* Nonzero if object's relocations done. */ + unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */ + unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs. */ + }; + +/* Internal functions of the run-time dynamic linker. + These can be accessed if you link again the dynamic linker + as a shared library, as in `-lld' or `/lib/ld.so' explicitly; + but are not normally of interest to user programs. + + The `-ldl' library functions in provide a simple + user interface to run-time dynamic linking. */ + + +/* File descriptor referring to the zero-fill device. */ +extern int _dl_zerofd; + +/* OS-dependent function to open the zero-fill device. */ +extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */ + +/* OS-dependent function to write a message on the standard output. + All arguments are `const char *'; args until a null pointer + are concatenated to form the message to print. */ +extern void _dl_sysdep_message (const char *string, ...); + +/* OS-dependent function to give a fatal error message and exit + when the dynamic linker fails before the program is fully linked. + All arguments are `const char *'; args until a null pointer + are concatenated to form the message to print. */ +extern void _dl_sysdep_fatal (const char *string, ...) + __attribute__ ((__noreturn__)); + +/* Nonzero if the program should be "secure" (i.e. it's setuid or somesuch). + This tells the dynamic linker to ignore environment variables. */ +extern int _dl_secure; + +/* This function is called by all the internal dynamic linker functions + when they encounter an error. ERRCODE is either an `errno' code or + zero; OBJECT is the name of the problematical shared object, or null if + it is a general problem; ERRSTRING is a string describing the specific + problem. */ + +extern void _dl_signal_error (int errcode, + const char *object, + const char *errstring) + __attribute__ ((__noreturn__)); + +/* Call OPERATE, catching errors from `dl_signal_error'. If there is no + error, *ERRSTRING is set to null. If there is an error, *ERRSTRING and + *OBJECT are set to the strings passed to _dl_signal_error, and the error + code passed is the return value. */ +extern int _dl_catch_error (const char **errstring, + const char **object, + void (*operate) (void)); + + +/* Helper function for functions. Runs the OPERATE function via + _dl_catch_error. Returns zero for success, nonzero for failure; and + arranges for `dlerror' to return the error details. */ +extern int _dlerror_run (void (*operate) (void)); + + +/* Open the shared object NAME and map in its segments. + LOADER's DT_RPATH is used in searching for NAME. + If the object is already opened, returns its existing map. */ +extern struct link_map *_dl_map_object (struct link_map *loader, + const char *name); + +/* Similar, but file found at REALNAME and opened on FD. + REALNAME must malloc'd storage and is used in internal data structures. */ +extern struct link_map *_dl_map_object_from_fd (const char *name, + int fd, char *realname); + +/* Cache the locations of MAP's hash table. */ +extern void _dl_setup_hash (struct link_map *map); + + +/* Search loaded objects' symbol tables for a definition of the symbol + referred to by UNDEF. *SYM is the symbol table entry containing the + reference; it is replaced with the defining symbol, and the base load + address of the defining object is returned. SYMBOL_SCOPE is the head of + the chain used for searching. REFERENCE_NAME should name the object + containing the reference; it is used in error messages. If NOSELF is + nonzero, them *SYM itself cannot define the value; another binding must + be found. */ +extern Elf32_Addr _dl_lookup_symbol (const char *undef_name, + const Elf32_Sym **ref, + struct elf_resolve *symbol_scope, + const char *reference_name, + int noself); + + +/* List of objects currently loaded. */ +extern struct link_map *_dl_loaded; + +/* Tail of that list which were loaded at startup. */ +extern struct link_map *_dl_startup_loaded; + +/* Allocate a `struct link_map' for a new object being loaded, + and enter it into the _dl_loaded list. */ +extern struct link_map *_dl_new_object (char *realname, const char *libname, + int type); + +/* Relocate the given object (if it hasn't already been). + If LAZY is nonzero, don't relocate its PLT. */ +extern void _dl_relocate_object (struct link_map *map, int lazy); + +/* Return the address of the next initializer function not yet run. + When there are no more initializers to be run, this returns zero. + The functions are returned in the order they should be called. */ +extern Elf32_Addr _dl_init_next (void); + +/* Call the finalizer functions of all shared objects whose + initializer functions have completed. */ +extern void _dl_fini (void); + +/* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' + says what change is taking place. This function's address is + the value of the `r_brk' member. */ +extern void _dl_r_debug_state (void); + +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(char * libname, int); + +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); + + + +#endif /* link.h */ diff --git a/gnu/libexec/ld.so/ld.so/mips/string.h b/gnu/libexec/ld.so/ld.so/mips/string.h new file mode 100644 index 00000000000..2728fd64940 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/string.h @@ -0,0 +1,303 @@ +#ifndef _DL_STRING_H_ +#define _DL_STRING_H_ + +#include /* for size_t */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern inline char *_dl_strcpy (char *dest, const char *src); +extern inline char *_dl_strncpy (char *dest, const char *src, size_t count); +extern inline char *_dl_strcat (char *dest, const char *src); +extern inline char *_dl_strncat (char *dest, const char *src, size_t count); +extern inline int _dl_strcmp (const char *cs, const char *ct); +extern inline int _dl_strncmp (const char *cs, const char *ct, size_t count); +extern inline char *_dl_strchr (const char *s, int c); +extern inline char *_dl_strrchr (const char *s, int c); +extern inline size_t _dl_strspn (const char *cs, const char *ct); +extern inline size_t _dl_strcspn (const char *cs, const char *ct); +extern inline char *_dl_strpbrk (const char *cs, const char *ct); +extern inline char *_dl_strstr (const char *cs, const char *ct); +extern inline size_t _dl_strlen (const char *s); +extern inline char *_dl_strtok (char *s, const char *ct); +extern inline void *_dl_memcpy (void *to, const void *from, size_t n); +extern inline void *_dl_memmove (void *dest, const void *src, size_t n); +extern inline int _dl_memcmp (const void *cs, const void *ct, size_t count); +extern inline void *_dl_memchr (const void *cs, int c, size_t count); +extern inline void *_dl_memset (void *s, int c, size_t count); + +/* Make sure we are using our inline version. */ +#define strlen(s) _dl_strlen(s) + +extern inline char * +_dl_strcpy (char *dest, const char *src) +{ + char *xdest = dest; + + while ((*dest++ = *src++) != '\0') + ; + return xdest; +} + +extern inline char * +_dl_strncpy (char *dest, const char *src, size_t n) +{ + char *xdest = dest; + + if (n == 0) + return xdest; + + while ((*dest = *src++) != '\0') + if (--n == 0) + break; + return xdest; +} + +extern inline char * +_dl_strcat (char *dest, const char *src) +{ + char *xdest = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return xdest; +} + +extern inline char * +_dl_strncat (char *dest, const char *src, size_t count) +{ + char *xdest = dest; + + if (count) + { + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + if (--count == 0) + break; + } + + return xdest; +} + +extern inline int +_dl_strcmp (const char *cs, const char *ct) +{ + char c; + + while ((c = *cs++) == *ct++) + if (c == 0) + return 0; + return c - *--ct; +} + +extern inline int +_dl_strncmp (const char *cs, const char *ct, size_t count) +{ + char c; + + if (!count) + return 0; + + while ((c = *cs++) == *ct++) + if (c == 0 || --count == 0) + return 0; + return c - *--ct; +} + +extern inline char * +_dl_strchr (const char *s, int c) +{ + const char ch = c; + + for (; *s != ch; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} + +extern inline char * +_dl_strrchr (const char * s, int c) +{ + char *res = NULL; + const char ch = c; + + for (;; ++s) + { + if (*s == ch) + res = (char *) s; + if (*s == '\0') + break; + } + return res; +} + +extern inline size_t +_dl_strspn (const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + ++count; + } + + return count; +} + +extern inline size_t +_dl_strcspn (const char *s, const char *reject) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = reject; *a != '\0'; ++a) + if (*p == *a) + return count; + ++count; + } + + return count; +} + +extern inline char * +_dl_strpbrk (const char *cs, const char *ct) +{ + const char *sc1, *sc2; + + for (sc1 = cs; *sc1 != '\0'; ++sc1) + for (sc2 = ct; *sc2 != '\0'; ++sc2) + if (*sc1 == *sc2) + return (char *) sc1; + return NULL; +} + +extern inline char * +_dl_strstr (const char *cs, const char *ct) +{ + const char *p; + + for (;; cs++) + { + for (p = ct; *p == *cs; p++, cs++) + if (*p == 0) + return (char *) cs - (p - ct); + cs -= p - ct; + if (*cs == 0) + return NULL; + } +} + +extern inline size_t +_dl_strlen (const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + ; + return sc - s; +} + +extern char * ___strtok; + +extern inline char * +_dl_strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) + return NULL; + sbegin += _dl_strspn (sbegin, ct); + if (*sbegin == '\0') + { + ___strtok = NULL; + return NULL; + } + send = _dl_strpbrk (sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return sbegin; +} + +extern inline void * +_dl_memcpy (void *to, const void *from, size_t n) +{ + char *cto = to; + const char *cfrom = from; + + while (n--) + *cto++ = *cfrom++; + return to; +} + +extern inline void * +_dl_memmove (void *dest, const void *src, size_t n) +{ + char *cdest = dest; + const char *csrc = src; + + if (dest < src) + { + while (n--) + *cdest++ = *csrc++; + } + else + { + cdest += n; + csrc += n; + while (n--) + *--cdest = *--csrc; + } + return dest; +} + +extern inline int +_dl_memcmp (const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + + for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--) + if (*su1 != *su2) + return *su1 < *su2 ? -1 : 1; + return 0; +} + +extern inline void * +_dl_memchr (const void *cs, int c, size_t count) +{ + const unsigned char ch = c; + const unsigned char *s = cs; + + for (; count != 0; ++s, count--) + if (*s == ch) + return (void *) s; + return NULL; +} + +extern inline void * +_dl_memset (void *s, int c, size_t count) +{ + char *cs = s; + + while (count--) + *cs++ = c; + return s; +} + +#endif diff --git a/gnu/libexec/ld.so/ld.so/mips/syscall.h b/gnu/libexec/ld.so/ld.so/mips/syscall.h new file mode 100644 index 00000000000..0ff1fbe5134 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/syscall.h @@ -0,0 +1,201 @@ +#ifdef USE_CACHE +#include +#endif + +#include + +#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 a bunch of syscalls that are required + 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. */ + +extern inline int +_dl_exit (int status) +{ + register int __status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "syscall" + : "=r" (__status) + : "0" (SYS_exit), "r" (status) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + while(1); +} + +extern inline int +_dl_open (const char* addr, unsigned int flags) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "syscall\n\t" + "beq $7,$0,1f\n\t" + "li $2,-1\n\t" + "1:" + : "=r" (status) + : "0" (SYS_open), "r" (addr), "r" (flags) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +extern inline int +_dl_close (int fd) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "syscall\n\t" + "beq $7,$0,1f\n\t" + "li $2,-1\n\t" + "1:" + : "=r" (status) + : "0" (SYS_close), "r" (fd) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +extern inline int +_dl_write (int fd, const char* buf, int len) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "move $6,%4\n\t" + "syscall\n\t" + "beq $7,$0,1f\n\t" + "li $2,-1\n\t" + "1:" + : "=r" (status) + : "0" (SYS_write), "r" (fd), "r" (buf), "r" (len) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +extern inline int +_dl_read (int fd, const char* buf, int len) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "move $6,%4\n\t" + "syscall\n\t" + "beq $7,$0,1f\n\t" + "li $2,-1\n\t" + "1:" + : "=r" (status) + : "0" (SYS_read), "r" (fd), "r" (buf), "r" (len) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +extern inline int +_dl_mmap (void *addr, unsigned int size, unsigned int prot, + unsigned int flags, int fd, unsigned int f_offset) +{ + register int malloc_buffer __asm__ ("$2"); + __asm__ volatile ("addiu $29,-40\n\t" + "move $6,%2\n\t" + "move $7,%3\n\t" + "sw %4,16($29)\n\t" + "sw %5,20($29)\n\t" +#ifdef MIPSEL + "li $4,197\n\t" + "li $5,0\n\t" + "sw %6,24($29)\n\t" + "sw $0,28($29)\n\t" + "sw %7,32($29)\n\t" + "sw $0,36($29)\n\t" +#endif +#ifdef MIPSEB + "li $4,0\n\t" + "li $5,197\n\t" + "sw %6,24($29)\n\t" + "sw $0,28($29)\n\t" + "sw $0,32($29)\n\t" + "sw %7,36($29)\n\t" +#endif + "syscall\n\t" + "addiu $29,40" + : "=r" (malloc_buffer) + : "0" (SYS___syscall), "r" (addr), "r" (size), "r" (prot), + "r" (flags), "r" (fd), "r" (f_offset) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return malloc_buffer; +} + +extern inline int +_dl_mprotect (const void *addr, int size, int prot) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "move $6,%4\n\t" + "syscall" + : "=r" (status) + : "0" (SYS_mprotect), "r" (addr), "r" (size), "r" (prot) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +#ifdef USE_CACHE +extern inline int +_dl_stat (const char *addr, struct stat *sb) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "syscall" + : "=r" (status) + : "0" (SYS_stat), "r" (addr), "r" (sb) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} + +extern inline int +_dl_munmap (const void *addr, unsigned int size) +{ + register int status __asm__ ("$2"); + __asm__ volatile ("move $4,%2\n\t" + "move $5,%3\n\t" + "syscall" + : "=r" (status) + : "0" (SYS_munmap), "r" (addr), "r" (size) + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$10","$11","$12","$13","$14","$15","$24","$25"); + return status; +} +#endif + +/* 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) +{ + unsigned int uid, euid, gid, egid; + + __asm__ volatile ("move $2,%1; syscall; move %0,$2" + : "=r" (uid) : "r" (SYS_getuid) : "$2"); + __asm__ volatile ("move $2,%1; syscall; move %0,$2" + : "=r" (euid) : "r" (SYS_geteuid) : "$2"); + __asm__ volatile ("move $2,%1; syscall; move %0,$2" + : "=r" (gid) : "r" (SYS_getgid) : "$2"); + __asm__ volatile ("move $2,%1; syscall; move %0,$2" + : "=r" (egid) : "r" (SYS_getegid) : "$2"); + + return (uid == euid && gid == egid); +} diff --git a/gnu/libexec/ld.so/ld.so/mips/sysdep.h b/gnu/libexec/ld.so/ld.so/mips/sysdep.h new file mode 100644 index 00000000000..52d3f874197 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/mips/sysdep.h @@ -0,0 +1,75 @@ + +/* 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) \ + asm(" addiu %0,$29,328" : "=r" (ARGVP)) + +/* Get the address of the Global offset table. This must be absolute, + not relative. This is already set up on mips */ +#define GET_GOT(X) + +/* + * Calculate how much off the link address we are loaded. + */ +static inline Elf32_Addr +elf_machine_load_offset (void) +{ + Elf32_Addr addr; + asm (" .set noreorder\n" + " la %0, here\n" + " bltzal $0, here\n" + " nop\n" + "here: subu %0, $31, %0\n" + " .set reorder\n" + : "=r" (addr)); + return addr; +} + +/* 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) \ + if(ELF32_R_TYPE((RELP)->r_info) == R_MIPS_REL32) { \ + if (ELF32_ST_BIND ((SYMBOL)->st_info) == STB_LOCAL \ + && (ELF32_ST_TYPE ((SYMBOL)->st_info) == STT_SECTION \ + || ELF32_ST_TYPE ((SYMBOL)->st_info) == STT_NOTYPE)) { \ + *(REL) += (LOAD); \ + } \ + else { \ + *(REL) = (LOAD) + (SYMBOL)->st_value; \ + } \ + } + +/* Transfer control to the user's application, once the dynamic loader + is done. t9 has to contain the entry (link) address */ + +#define START() \ + __asm__ volatile ("move $25, %0\n\t" \ + "move $29, %1\n\t" \ + "jr $25" \ + : : "r" (_dl_elf_main), "r" (stack)); + + + +/* Here we define the magic numbers that this dynamic loader should accept */ + +#define MAGIC1 EM_MIPS +#undef MAGIC2 +/* Used for error messages */ +#define ELF_TARGET "mips" + +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 mips. */ +#define do_rem(result, n, base) ((result) = (n) % (base)) diff --git a/gnu/libexec/ld.so/ld.so/readelflib1.c b/gnu/libexec/ld.so/ld.so/readelflib1.c new file mode 100644 index 00000000000..2fad8ec0450 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/readelflib1.c @@ -0,0 +1,470 @@ +/* Load an ELF sharable library into memory. + + 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. */ + + + +/* This file contains the helper routines to load an ELF sharable + library into memory and add the symbol table info to the chain. */ + +#include +#include +#include +#include +#include +#include "hash.h" +#include "sysdep.h" +#include +#include "syscall.h" +#include "string.h" +#ifdef USE_CACHE +#include "../config.h" +#endif + +extern char *_dl_progname; +extern _dl_runtime_resolve(void); + +#ifdef USE_CACHE + +static caddr_t _dl_cache_addr = NULL; +static size_t _dl_cache_size = 0; + +int _dl_map_cache(void) +{ + int fd; + struct stat st; + header_t *header; + + if (_dl_cache_addr != NULL) + return -1; + + 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_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) + { + _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE); + goto fail; + } + + if (_dl_memcmp (header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)) + { + _dl_fdprintf(2, "%s: cache '%s' has wrong version\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; + + _dl_munmap (_dl_cache_addr, _dl_cache_size); + _dl_cache_addr = NULL; + + 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(struct dyn_elf * dpnt, + char * full_libname){ + char * pnt, *pnt1, *pnt2; + struct elf_resolve * tpnt, *tpnt1; + char mylibname[1024]; + char * libname; + + _dl_internal_error_number = 0; + 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. */ + + if (libname != full_libname) { + tpnt1 = _dl_load_elf_shared_library(full_libname, 0); + if (tpnt1) + return tpnt1; + goto goof; + } + + /* 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 != ';') *pnt2++ = *pnt1++; + if(pnt2[-1] != '/') *pnt2++ = '/'; + pnt = libname; + while(*pnt) *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = _dl_load_elf_shared_library(mylibname, 0); + if(tpnt1) return tpnt1; + if(*pnt1 == ':' || *pnt1 == ';') pnt1++; + } + } + +#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 && + _dl_strcmp(libname, strs+libent[i].sooffset) == 0 && + (tpnt1 = _dl_load_elf_shared_library(strs+libent[i].liboffset, 0))) + return tpnt1; + } + } +#endif + + /* Check in rpath directories */ + for(; dpnt; dpnt = dpnt->next) { + tpnt = dpnt->dyn; + pnt1 = (char *) tpnt->dynamic_info[DT_RPATH]; + if(pnt1) { + pnt1 += (unsigned int) tpnt->loadoffs + tpnt->dynamic_info[DT_STRTAB]; + while(*pnt1){ + pnt2 = mylibname; + while(*pnt1 && *pnt1 != ':') *pnt2++ = *pnt1++; + if(pnt2[-1] != '/') *pnt2++ = '/'; + pnt = libname; + while(*pnt) *pnt2++ = *pnt++; + *pnt2++ = 0; + tpnt1 = _dl_load_elf_shared_library(mylibname, 0); + if(tpnt1) return tpnt1; + if(*pnt1 == ':') pnt1++; + } + } + } + + /* 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(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(mylibname, 0); + if (tpnt1) return tpnt1; + +goof: + /* Well, we shot our wad on that one. All we can do now is punt */ + if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number; + else _dl_error_number = 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. + */ + +struct elf_resolve * _dl_load_elf_shared_library(char * libname, int flag){ + Elf32_Ehdr * epnt; + unsigned int dynamic_addr = 0; + unsigned int dynamic_size = 0; + Elf32_Dyn * dpnt; + struct elf_resolve * tpnt; + Elf32_Phdr * ppnt; + int piclib; + char * status; + int flags; + char header[4096]; + int dynamic_info[DT_NUM + DT_MDEP]; + int * lpnt; + unsigned int libaddr; + unsigned int liboffs; + 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; + + libaddr = 0; + liboffs = 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 = (Elf32_Ehdr *) 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 = (Elf32_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_COPY; + if(!piclib) flags|=MAP_FIXED; + + status = (char *) _dl_mmap((char *) (piclib?0:minvma), + maxvma-minvma, + PROT_NONE, + flags | MAP_ANON, -1, + 0); + if(_dl_mmap_check_error(status)) { + _dl_fdprintf(2, "%s: can't map 'zero'\n", _dl_progname); + _dl_internal_error_number = DL_ERROR_MMAP_FAILED; + _dl_close(infile); + return NULL; + }; + libaddr=(unsigned int)status; + liboffs = libaddr - minvma; + flags|=MAP_FIXED; + + /* Get the memory to store the library */ + ppnt = (Elf32_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 *) (libaddr - minvma + + (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; + }; + + if(!piclib) status = 0; + + /* Pad the last page with zeros. */ + 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 zerofill if + there are any pages left over that are not mapped as part of the file */ + + map_size = (ppnt->p_vaddr - minvma + ppnt->p_filesz + 0xfff) & 0xfffff000; + if(map_size < ppnt->p_vaddr - minvma + ppnt->p_memsz) + status = (char *) _dl_mmap((char *) map_size + libaddr, + ppnt->p_vaddr - minvma + ppnt->p_memsz - map_size, + LXFLAGS(ppnt->p_flags), + flags | MAP_ANON, -1, 0); + } else + status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) + + libaddr - minvma, + ((ppnt->p_vaddr - minvma) & 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) libaddr = 0; + + dynamic_addr -= (unsigned int) minvma; + 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 = (Elf32_Dyn *) dynamic_addr; + + _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); + while(dpnt->d_tag != DT_NULL) { + if(dpnt->d_tag < DT_NUM) { + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + } + else if(dpnt->d_tag >= DT_LOPROC && dpnt->d_tag < DT_LOPROC + DT_MDEP) { + dynamic_info[dpnt->d_tag - DT_LOPROC + DT_NUM] = dpnt->d_un.d_val; + } + if(dpnt->d_tag == DT_TEXTREL) + dynamic_info[DT_TEXTREL] = 1; + dpnt++; + } + dynamic_size = dpnt - (Elf32_Dyn *) dynamic_addr; + + tpnt = _dl_add_elf_hash_table(libname, (char *)libaddr, (char *)liboffs, + dynamic_info, dynamic_addr, dynamic_size); + + tpnt->ppnt = (Elf32_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)liboffs)); + lpnt[0] = (int)_dl_runtime_resolve; + if(lpnt[1] & 0x80000000) + lpnt[1] = (Elf32_Addr) ((unsigned) tpnt | 0x80000000); + }; + + return tpnt; +} + diff --git a/gnu/libexec/ld.so/ld.so/sparc/Makefile b/gnu/libexec/ld.so/ld.so/sparc/Makefile new file mode 100644 index 00000000000..6f5ba5685db --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/Makefile @@ -0,0 +1,49 @@ +include ../../Version.mk +include ../../Config.mk + +CC = $(ELFCC) +AS = $(ELFAS) +LD = $(ELFLD) + +CFLAGS += -I.. -I. -DNO_UNDERSCORE -DVERBOSE_DLINKER +CFLAGS += -fPIC -D__PIC__ #-DDEBUG # -funroll-loops + +../%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ +../%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +SRC1S = resolve.S +SRC2S = elfinterp.c + +SRCS = $(SRC1S) $(SRC2S) +OBJ1S = $(SRC1S:.S=.o) +OBJ2S = $(SRC2S:.c=.o) +OBJS = $(OBJ1S) $(OBJ2S) + +DLINK_OBJS:= $(addprefix ../, $(OBJS)) + +lib:: $(DLINK_OBJS) + +obj: $(DLINK_OBJS) + +asm: $(ASMS) + +realclean:: + $(RM) -f .depend core *.o *.a *.s *.i tmp_make *~ + +clean:: + $(RM) -f core *.o *.a *.s *.i tmp_make *~ + +depend:: + $(CC) $(CFLAGS) -M $(SRCS) | \ + sed -e 's,^[ ]*\(.*\.o\)[ ]*:,../\1:,' > .depend +# $(MAKE) subdir TARGET=depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gnu/libexec/ld.so/ld.so/sparc/elfinterp.c b/gnu/libexec/ld.so/ld.so/sparc/elfinterp.c new file mode 100644 index 00000000000..cb1bfe2ac52 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/elfinterp.c @@ -0,0 +1,339 @@ +/* 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 +#include +#include +#include +#ifdef IBCS_COMPATIBLE +#include +#else +#include +#endif +#include +#include "hash.h" +#include "linuxelf.h" +#include "syscall.h" +#include "sysdep.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) { + _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_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(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 */ + +#ifndef BROKEN_LINKER +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++; + }; + }; + _dl_memcpy((char *) symtab[symtab_index].st_value, + (char *) symbol_addr, + symtab[symtab_index].st_size); + }; + return goof; +} +#endif + + diff --git a/gnu/libexec/ld.so/ld.so/sparc/resolve.S b/gnu/libexec/ld.so/ld.so/sparc/resolve.S new file mode 100644 index 00000000000..ea985b5c873 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/resolve.S @@ -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 diff --git a/gnu/libexec/ld.so/ld.so/sparc/string.h b/gnu/libexec/ld.so/ld.so/sparc/string.h new file mode 100644 index 00000000000..3e6e099a42d --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/string.h @@ -0,0 +1,326 @@ +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +/* string.h: External definitions for optimized assembly string + routines for the Linux Kernel. + + Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + Adapted for linux ELF dynamic loader by Eric Youngdale(eric@aib.com). +*/ + + +#include /* for size_t */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +extern inline size_t _dl_strlen(const char * s); +extern inline int _dl_strcmp(const char * cs,const char * ct); +extern inline int _dl_strncmp(const char * cs,const char * ct,size_t count); +extern inline char * _dl_strcpy(char * dest,const char *src); +extern inline char * _dl_strncpy(char * dest,const char *src,size_t count); +extern inline char * _dl_strcat(char * dest,const char * src); +extern inline char * _dl_strncat(char * dest,const char * src,size_t count); +extern inline char * _dl_strchr(const char * s,char c); +extern inline char * _dl_strpbrk(const char * cs,const char * ct); +extern inline size_t _dl_strspn(const char * cs, const char * ct); +extern inline char * _dl_strtok(char * s,const char * ct); +extern inline void * _dl_memset(void * s,char c,size_t count); +extern inline void * _dl_memcpy(void * to, const void * from, size_t n); +extern inline void * _dl_memmove(void * dest,const void * src, size_t n); +extern inline int _dl_memcmp(const void * cs,const void * ct,size_t count); + +extern __inline__ size_t _dl_strlen(const char * s1) +{ + int count = 0; + while( *s1++ != '\0') + { + count++; + } + + return count;; +} + +extern __inline__ int _dl_strcmp(const char * s1, + const char * s2) +{ + while( *s1 != '\0' && *s2 != '\0' ) + { + if( *s1 != *s2 ) + return *s1 - *s2; + s1++; + s2++; + } + + return *s1 - *s2; +} + +extern __inline__ int _dl_strncmp(const char* str1, const char* str2, size_t strlen) +{ + register int retval=0; + + __asm__("cmp %3, 0x0\n\t" + "be 2f\n\t" + "ldub [%2], %%g3\n\t" + "1: ldub [%1], %%g2\n\t" + "sub %%g2, %%g3, %0\n\t" + "cmp %0, 0x0\n\t" + "bne 2f\n\t" + "add %2, 0x1, %2\n\t" + "cmp %%g2, 0x0\n\t" + "be 2f\n\t" + "add %1, 0x1, %1\n\t" + "addcc %3, -1, %3\n\t" + "bne,a 1b\n\t" + "ldub [%2], %%g3\n\t" + "2: " : + "=r" (retval), "=r" (str1), "=r" (str2), "=r" (strlen) : + "0" (retval), "1" (str1), "2" (str2), "3" (strlen) : + "%g2", "%g3"); + + return retval; +} + + +extern __inline__ char *_dl_strcpy(char* dest, const char* source) +{ + register char tmp; + register char *retval; + + __asm__("or %%g0, %2, %0\n\t" + "ldub [%1], %3\n\t" + "1: stb %3, [%2]\n\t" + "cmp %3, 0x0\n\t" + "bne,a 1b\n\t" + "ldub [%1], %3\n\t" : + "=r" (retval), "=r" (source), "=r" (dest), "=r" (tmp) : + "0" (retval), "1" (source), "2" (dest), "3" (tmp)); + + return retval; +} + +extern __inline__ char *_dl_strncpy(char *dest, const char *source, size_t cpylen) +{ + register char tmp; + register char *retval; + + __asm__("or %%g0, %1, %0\n\t" + "1: cmp %4, 0x0\n\t" + "be 2f\n\t" + "ldub [%1], %3\n\t" + "add %1, 0x1, %1\n\t" + "stb %3, [%2]\n\t" + "sub %4, 0x1, %4\n\t" + "ba 1\n\t" + "add %2, 0x1, %2\n\t" : + "=r" (retval), "=r" (dest), "=r" (source), "=r"(tmp), "=r" (cpylen) : + "0" (retval), "1" (dest), "2" (source), + "3" (tmp), "4" (cpylen)); + + return retval; +} + +extern __inline__ char *_dl_strcat(char *dest, const char *src) +{ + register char *retval; + register char temp=0; + + __asm__("or %%g0, %1, %0\n\t" + "1: ldub [%1], %3\n\t" + "cmp %3, 0x0\n\t" + "bne,a 1b\n\t" + "add %1, 0x1, %1\n\t" + "2: ldub [%2], %3\n\t" + "stb %3, [%1]\n\t" + "add %1, 0x1, %1\n\t" + "cmp %3, 0x0\n\t" + "bne 2b\n\t" + "add %2, 0x1, %2\n\t" : + "=r" (retval), "=r" (dest), "=r" (src), "=r" (temp) : + "0" (retval), "1" (dest), "2" (src), "3" (temp)); + + return retval; +} + +extern __inline__ char *_dl_strncat(char *dest, const char *src, size_t len) +{ + register char *retval; + register char temp=0; + + __asm__("or %%g0, %1, %0\n\t" + "1: ldub [%1], %3\n\t" + "cmp %3, 0x0\n\t" + "bne,a 1b\n\t" + "add %1, 0x1, %1\n\t" + "2: ldub [%2], %3\n\t" + "stb %3, [%1]\n\t" + "add %1, 0x1, %1\n\t" + "add %3, -1, %3\n\t" + "cmp %3, 0x0\n\t" + "bne 2b\n\t" + "add %2, 0x1, %2\n\t" : + "=r" (retval), "=r" (dest), "=r" (src), "=r" (len), "=r" (temp) : + "0" (retval), "1" (dest), "2" (src), "3" (len), "4" (temp)); + + return retval; +} + +extern __inline__ char *_dl_strchr(const char *src, char c) +{ + register char temp=0; + register char *trick=0; + + __asm__("1: ldub [%0], %2\n\t" + "cmp %2, %1\n\t" + "bne,a 1b\n\t" + "add %0, 0x1, %0\n\t" + "or %%g0, %0, %3\n\t" : + "=r" (src), "=r" (c), "=r" (temp), "=r" (trick), "=r" (src) : + "0" (src), "1" (c), "2" (temp), "3" (trick), "4" (src)); + + return trick; +} + +extern __inline__ char *_dl_strpbrk(const char *cs, const char *ct) +{ + register char temp1, temp2; + register char *scratch; + register char *trick; + + __asm__("or %%g0, %1, %4\n\t" + "1: ldub [%0], %2\n\t" + "2: ldub [%1], %3\n\t" + "cmp %3, %2\n\t" + "be 3f\n\t" + "nop\n\t" + "cmp %3, 0x0\n\t" + "bne 2b\n\t" + "add %1, 0x1, %1\n\t" + "or %%g0, %4, %1\n\t" + "b 1b\n\t" + "add %0, 0x1, %0\n\t" + "or %%g0, %0, %5\n\t" : + "=r" (cs) : + "r" (ct), "r" (temp1), "r" (temp2), "r" (scratch), "r" (trick=0), + "0" (cs), "1" (ct)); + + return trick; + +} + + +extern __inline__ size_t _dl_strspn(const char *s, const char *accept) +{ + register char temp1, temp2; + register char* scratch; + register size_t trick; + + __asm__("or %%g0, %1, %4\n\t" + "1: ldub [%0], %2\n\t" + "2: ldub [%1], %3\n\t" + "cmp %3, 0x0\n\t" + "be 3f\n\t" + "cmp %3, %2" + "bne 2b\n\t" + "add %1, 0x1, %1\n\t" + "add %0, 0x1, %0\n\t" + "b 1b\n\t" + "add %5, 0x1, %5\n\t" + "3: or %%g0, %0, %4\n\t" : + "=r" (s) : + "r" (accept), "r" (temp1), "r" (temp2), + "r" (scratch), "r" (trick=0), "0" (s)); + + return trick; + +} + +extern __inline__ void *_dl_memset(void *src, char c, size_t count) +{ + register char *retval; + + retval = (char *) src; + while(count--) + { + *retval++ = c; + } +} + +extern __inline__ void *_dl_memcpy(void *dest, const void *src, size_t count) +{ + register void *retval; + register char tmp; + + __asm__("or %%g0, %1, %0\n\t" + "add %3, -1, %3\n\t" + "cmp %3, -1\n\t" + "be 2f\n\t" + "1: ldub [%2], %4\n\t" + "add %2, 0x1, %2\n\t" + "add %3, -1, %3\n\t" + "cmp %3, -1\n\t" + "stb %4, [%1]\n\t" + "bne 1b\n\t" + "add %1, 0x1, %1\n\t" + "2: " : + "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) : + "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp)); + + return retval; +} + +extern __inline__ void *_dl_memmove(void *dest, const void *src, size_t count) +{ + register void *retval; + register char tmp; + + __asm__("or %%g0, %1, %1\n\t" + "add %3, -1, %3\n\t" + "cmp %3, -1\n\t" + "be 2f\n\t" + "1: ldub [%2], %4\n\t" + "add %2, 0x1, %2\n\t" + "add %3, -1, %3\n\t" + "cmp %3, -1\n\t" + "stb %4, [%1]\n\t" + "bne 1b\n\t" + "add %1, 0x1, %1\n\t" + "2: " : + "=r" (retval), "=r" (dest), "=r" (src), "=r" (count), "=r" (tmp) : + "0" (retval), "1" (dest), "2" (src), "3" (count), "4" (tmp)); + + return retval; +} + +extern __inline__ int _dl_memcmp(const void *cs, const void *ct, size_t count) +{ + register int retval; + register unsigned long tmp1, tmp2; + + __asm__("or %%g0, %1, %0\n\t" + "cmp %3, 0x0\n\t" + "ble,a 3f\n\t" + "or %%g0, %%g0, %0\n\t" + "1: ldub [%1], %4\n\t" + "ldub [%2], %5\n\t" + "cmp %4, %5\n\t" + "be,a 2f\n\t" + "add %1, 0x1, %1\n\t" + "bgeu 3f\n\t" + "or %%g0, 0x1, %0\n\t" + "b 3f\n\t" + "or %%g0, -1, %0\n\t" + "2: add %3, -1, %3\n\t" + "cmp %3, 0x0\n\t" + "bg 1b\n\t" + "add %2, 0x1, %2\n\t" + "or %%g0, %%g0, %0\n\t" + "3: " : + "=r" (retval) : + "r" (cs), "r" (ct), "r" (count), "r" (tmp1=0), "r" (tmp2=0)); + + return retval; +} + +#endif diff --git a/gnu/libexec/ld.so/ld.so/sparc/syscall.h b/gnu/libexec/ld.so/ld.so/sparc/syscall.h new file mode 100644 index 00000000000..2beb9f403e2 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/syscall.h @@ -0,0 +1,249 @@ + +extern inline volatile void _dl_exit(int status); +extern inline volatile void _dl_close(int fd); +extern inline int _dl_mmap(void * addr, unsigned int size, + unsigned int prot, + unsigned int flags, int fd, + unsigned int f_offset); +#ifndef _dl_MAX_ERRNO +#define _dl_MAX_ERRNO 4096 +#endif +#define _dl_mmap_check_error(__res) \ + (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO) +extern inline int _dl_open(char * addr, unsigned int flags); +extern inline int _dl_write(int fd, const char * buf, int len); +extern inline int _dl_read(int fd, const char * buf, int len); +extern inline int _dl_mprotect(const char * addr, int size, int prot); +#include +extern inline int _dl_stat(char * filename, struct stat *st); +extern inline int _dl_munmap(char * addr, int size); + +/* Here are the definitions for a bunch of syscalls that are required + 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. */ + +#ifdef SOLARIS_COMPATIBLE +#include "/usr/include/sys/syscall.h" +#endif + +extern inline volatile void _dl_exit(int status) +{ + int __res; + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "ta 8" \ + : "=r" (__res) : "i" (__NR_exit),"r" ((long)(status))); +} + +extern inline volatile void _dl_close(int fd) +{ + int status; + + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (status) \ + : "i" (__NR_close),"r" ((long)(fd)) + : "o0", "g1"); + +} + +extern inline int _dl_mmap(void * addr, unsigned int size, + unsigned int prot, + unsigned int flags, int fd, + unsigned int f_offset) +{ + int malloc_buffer; +#ifdef SOLARIS_COMPATIBLE + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "sethi %%hi(0x80000000), %%o3\n\t" \ + "or %%o3, %5, %%o3\n\t" \ + "or %%g0, %6, %%o4\n\t" \ + "or %%g0, %7, %%o5\n\t" \ + "ta 8\n\t" \ + "mov %%o0, %0\n\t" + : "=r" (malloc_buffer) : "0" (SYS_mmap), + "r" (addr), "r" (size), "r" (prot), "r" (flags), + "r" (fd), "r" (f_offset) + : "g1", "o0", "o1", "o2", "o3", "o4", "o5"); +#else + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "or %%g0, %5, %%o3\n\t" \ + "or %%g0, %6, %%o4\n\t" \ + "or %%g0, %7, %%o5\n\t" \ + "ta 8\n\t" \ + "mov %%o0, %0\n\t" + : "=r" (malloc_buffer) : "0" (__NR_mmap), + "r" (addr), "r" (size), "r" (prot), "r" (flags), + "r" (fd), "r" (f_offset) + : "g1", "o0", "o1", "o2", "o3", "o4", "o5"); +#endif + return malloc_buffer; +} + + +extern inline int _dl_open(char * addr, unsigned int flags) +{ + int zfileno; + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, 0, %%o2\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (zfileno) \ + : "i" (__NR_open),"r" ((long)(addr)),"r" ((long)(flags)) + : "g1", "o0", "o1", "o2"); + + return zfileno; +} + +extern inline int _dl_write(int fd, const char * buf, int len) +{ + int status; + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (status) \ + : "i" (__NR_write),"r" ((long)(fd)),"r" ((long)(buf)),"r" ((long)(len)) + : "g1", "o0", "o1", "o2"); +} + + +extern inline int _dl_read(int fd, const char * buf, int len) +{ + int status; + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (status) \ + : "i" (__NR_read),"r" ((long)(fd)),"r" ((long)(buf)),"r" ((long)(len)) + : "g1", "o0", "o1", "o2"); +} + +extern inline int _dl_mprotect(const char * addr, int size, int prot) +{ + int status; +#ifdef SOLARIS_COMPATIBLE + __asm__ volatile ( "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "mov %1,%%g1\n"\ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (status) \ + : "i" (SYS_mprotect),"r" ((long)(addr)),"r" ((long)(size)),"r" ((long)(prot)) + : "g1", "o0", "o1", "o2"); +#else + __asm__ volatile ( "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "or %%g0, %4, %%o2\n\t" \ + "mov %1,%%g1\n"\ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (status) \ + : "i" (__NR_mprotect),"r" ((long)(addr)),"r" ((long)(size)),"r" ((long)(prot)) + : "g1", "o0", "o1", "o2"); +#endif + return status; +} + +extern inline int _dl_stat(char * filename, struct stat *st) +{ + int ret; +#ifdef SOLARIS_COMPATIBLE + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (ret) \ + : "i" (SYS_stat),"r" (filename),"r" (st) + : "g1", "o0", "o1"); + + +#else + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (ret) \ + : "i" (__NR_stat),"r" (filename),"r" (st) + : "g1", "o0", "o1"); + + +#endif + return ret; +} + +extern inline int _dl_munmap(char * addr, int size) +{ + int ret; + __asm__ volatile ("mov %1,%%g1\n"\ + "or %%g0, %2, %%o0\n\t" \ + "or %%g0, %3, %%o1\n\t" \ + "ta 8\n" \ + "mov %%o0, %0\n\t" + : "=r" (ret) \ + : "i" (__NR_munmap),"r" ((long)(addr)),"r" ((long)(size)) + : "g1", "o0", "o1"); + + return ret; +} + +/* + * 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) +{ + unsigned int uid, euid, gid, egid; + euid = egid = 0; /* So compiler does not warn us */ + +#ifdef SOLARIS_COMPATIBLE + __asm__ volatile ("mov %2,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + "mov %%o1, %1\n\t" + : "=r" (uid) , "=r" (euid) : "i" (SYS_getuid) : "g1"); + __asm__ volatile ("mov %2,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + "mov %%o1, %1\n\t" + : "=r" (gid), "=r" (euid) : "i" (__NR_getgid) : "g1"); +#else + __asm__ volatile ("mov %1,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + : "=r" (uid) : "i" (__NR_getuid) : "g1"); + __asm__ volatile ("mov %1,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + : "=r" (euid) : "i" (__NR_geteuid) : "g1"); + __asm__ volatile ("mov %1,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + : "=r" (gid) : "i" (__NR_getgid) : "g1"); + __asm__ volatile ("mov %1,%%g1\nta 8\n\t" + "mov %%o0, %0\n\t" + : "=r" (egid) : "i" (__NR_getegid) : "g1"); +#endif + + if(uid == euid && gid == egid) + return 1; + else + return 0; +} diff --git a/gnu/libexec/ld.so/ld.so/sparc/sysdep.h b/gnu/libexec/ld.so/ld.so/sparc/sysdep.h new file mode 100644 index 00000000000..064059ac8c3 --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/sparc/sysdep.h @@ -0,0 +1,126 @@ + +/* + * 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 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_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)) + + + +/* 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. + */ +#define do_div(n,base) ({ \ +volatile int __res; \ +__asm__("mov %%g0,%%Y\n\t" \ + "sdiv %2,%3,%0\n\t" \ + :"=r" (n),"=r" (__res):"r" (n),"r"(base)); __res; }) + + +#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; }) + +/* + * dbx wants the binder to have a specific name. Mustn't disappoint it. + */ +#ifdef SOLARIS_COMPATIBLE +#define _dl_linux_resolve _elf_rtbndr +#endif + diff --git a/gnu/libexec/ld.so/ld.so/vsprintf.c b/gnu/libexec/ld.so/ld.so/vsprintf.c new file mode 100644 index 00000000000..a04c0a437fb --- /dev/null +++ b/gnu/libexec/ld.so/ld.so/vsprintf.c @@ -0,0 +1,238 @@ +/* Adapted for ELF dynamic linker - Mitch + * + * vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds and Lars Wirzenius + * + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ +#include +#include +#include +#include +#include "hash.h" +#include "string.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 SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (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[(unsigned)num % base]; + (unsigned)num /= base; + } + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int _dl_fdprintf(int fd, const char *fmt, ...) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + 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 */ + char buf[1024]; + va_list args; + + va_start(args, fmt); + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *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 == '*') { + /* 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 == '*') { + /* 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; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + len = _dl_strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + _dl_write(fd, buf, str-buf); + return str-buf; +} + diff --git a/gnu/libexec/ld.so/ldconfig/Makefile b/gnu/libexec/ld.so/ldconfig/Makefile new file mode 100644 index 00000000000..879737f96e6 --- /dev/null +++ b/gnu/libexec/ld.so/ldconfig/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 1996/09/18 08:16:06 pefo Exp $ + +PROG= ldconfig +SRCS= ldconfig.c readelf.c +MAN= ldconfig.8 + +BINDIR= /sbin + +.include + + diff --git a/gnu/libexec/ld.so/ldconfig/ld.so.conf b/gnu/libexec/ld.so/ldconfig/ld.so.conf new file mode 100644 index 00000000000..dfa65edb858 --- /dev/null +++ b/gnu/libexec/ld.so/ldconfig/ld.so.conf @@ -0,0 +1,2 @@ +/usr/local/lib +/usr/X11R6/lib diff --git a/gnu/libexec/ld.so/ldconfig/ldconfig.8 b/gnu/libexec/ld.so/ldconfig/ldconfig.8 new file mode 100644 index 00000000000..7bb663df73b --- /dev/null +++ b/gnu/libexec/ld.so/ldconfig/ldconfig.8 @@ -0,0 +1,142 @@ +.TH ldconfig 8 "30 March 1995" +.SH NAME +ldconfig \- determine run-time link bindings +.SH SYNOPSIS +ldconfig +[ +.B \-DvnNX +] +.IR directory \ ... +.PD 0 +.PP +.PD +ldconfig +.B \-l +[ +.B \-Dv +] +.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 directory +.RI ( /usr/lib ). +.I ldconfig +checks the header and file names of the DLL's it encounters when +determining which versions should have their links updated. +.PP +.I 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. +.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 \-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 + +/etc/ldconfig -v + +.RE +will set up the correct links for the shared binaries and rebuild +the cache. +.TP +On the command line +.RS + +# /etc/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 /var/run/ld.so.cache +File containing an ordered list of libraries found in the directories +specified in +.BR /etc/ld.so.conf . +.TP +.B lib*.so.version +shared libraries +.PD +.SH SEE ALSO +.BR ldd (1), +.BR ld.so (8). +.SH BUGS +.LP +.BR ldconfig 's +functionality, in conjunction with +.BR ld.so , +is only available for executables compiled using libc version 4.4.3 or greater. +.PP +.BR ldconfig , +being a user process, must be run manually and has no means of dynamically +determining and relinking shared libraries for use by +.BR ld.so +when a new DLL is installed. +.SH AUTHORS +David Engel and Mitch D'Souza. diff --git a/gnu/libexec/ld.so/ldconfig/ldconfig.c b/gnu/libexec/ld.so/ldconfig/ldconfig.c new file mode 100644 index 00000000000..bd32b114e8d --- /dev/null +++ b/gnu/libexec/ld.so/ldconfig/ldconfig.c @@ -0,0 +1,658 @@ +/* + * ldconfig - update shared library symlinks + * + * usage: ldconfig [-DvnNX] dir ... + * ldconfig -l [-Dv] lib ... + * ldconfig -p + * -D: debug mode, don't update links + * -v: verbose mode, print things as we go + * -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 + * dir ...: directories to process + * lib ...: libraries to link + * + * Copyright 1994, 1995 David Engel and Mitch D'Souza + * + * This program may be used for any purpose as long as this + * copyright notice is kept. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" + +char *___strtok = NULL; + +/* For SunOS */ +#ifndef PATH_MAX +#include +#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 *cachefile = LDSO_CACHE; /* default cache file */ +void cache_print(void); +void cache_dolib(char *dir, char *so, char *lib, int); +void cache_rmlib(char *dir, char *so); +void cache_write(void); + +char *readsoname(FILE *file); + +void warn(char *fmt, ...) +{ + va_list ap; + + 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; + + 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(char *str) +{ + char *ptr; + char *strdup(const char *); + 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 */ +char *is_shlib(char *dir, char *name, int *type) +{ + char *good = NULL; + char *cp, *cp2; + FILE *file; + struct exec exec; + Elf32_Ehdr *elf_hdr; + struct stat statbuf; + char buff[1024]; + + /* see if name is of the form libZ.so.V */ + if (strncmp(name, "lib", 3) == 0 && + (cp = strstr(name, ".so.")) && cp[4]) + { + /* find the start of the Vminor part, if any */ + if ((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_ISLNK(statbuf.st_mode) && stat(buff, &statbuf)) + { + if (verbose) + warn("%s is a stale symlink, removing", buff); + if (unlink(buff)) + warn("can't unlink %s (%s), skipping", buff, + strerror(errno)); + } + else if (!S_ISREG(statbuf.st_mode)) + warn("%s is not a regular file, skipping", buff, strerror(errno)); + else + { + /* 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 DLL or ELF library */ + if (fread(&exec, sizeof exec, 1, file) < 1) + warn("can't read header from %s, skipping", buff); + else + { + elf_hdr = (Elf32_Ehdr *) &exec; + if (elf_hdr->e_ident[0] != 0x7f || + strncmp(&elf_hdr->e_ident[1], "ELF",3) != 0) + warn("%s is not a DLL or ELF library, skipping", buff); + else + { + if ((good = readsoname(file)) == NULL) + good = xstrdup(name); + *type = LIB_ELF; + } + } + fclose(file); + } + } + } + + return good; +} + +/* update the symlink to new library */ +void link_shlib(char *dir, char *file, char *so) +{ + int change = -1; + char libname[1024]; + char linkname[1024]; + 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 && !nolinks) + { + if (!lstat(linkname, &linkstat) && remove(linkname)) + warn("can't unlink %s (%s)", linkname, strerror(errno)); + else if (symlink(file, linkname)) + warn("can't link %s to %s (%s)", linkname, file, strerror(errno)); + else + change = 1; + } + + /* some people like to know what we're doing */ + if (verbose) + 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 (*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 */ + struct lib *next; /* next library in list */ +}; + +/* update all shared library links in a directory */ +void scan_dir(char *name) +{ + DIR *dir; + struct dirent *ent; + char *so; + struct lib *lp, *libs = NULL; + int libtype; + + /* let 'em know what's going on */ + if (verbose) + 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)) == NULL) + continue; + + if (!nocache) + cache_dolib(name, so, ent->d_name, libtype); + + /* 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 (libcmp(ent->d_name, lp->name) > 0) + { + /* let's use the new one */ + free(lp->name); + lp->name = xstrdup(ent->d_name); + } + 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->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) + { + link_shlib(name, lp->name, lp->so); + if (strcmp(lp->name, lp->so) != 0) + cache_rmlib(name, lp->so); + } + + /* 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 *cp = NULL; + FILE *file; + struct stat stat; + + if ((file = fopen(LDSO_CONF, "r")) != NULL) + { + fstat(fileno(file), &stat); + cp = xmalloc(stat.st_size + 1); + fread(cp, 1, stat.st_size, file); + fclose(file); + cp[stat.st_size] = '\0'; + } + + return cp; +} + +int main(int argc, char **argv) +{ + int i, c; + int nodefault = 0; + int printcache = 0; + char *cp, *dir, *so; + char *extpath; + int libtype; + + prog = argv[0]; + opterr = 0; + + while ((c = getopt(argc, argv, "DvnNXlpf:")) != EOF) + switch (c) + { + case 'D': + debug = 1; /* debug mode */ + nocache = 1; + nolinks = 1; + verbose = 1; + break; + case 'v': + verbose = 1; /* verbose 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; + default: + fprintf(stderr, "usage: %s [-DvnNX] dir ...\n", prog); + fprintf(stderr, " %s -l [-Dv] lib ...\n", prog); + fprintf(stderr, " %s -p\n", prog); + exit(EXIT_FATAL); + break; + + /* THE REST OF THESE ARE UNDOCUMENTED AND MAY BE REMOVED + IN FUTURE VERSIONS. */ + case 'f': + cachefile = optarg; /* alternate cache file */ + break; + } + + /* allow me to introduce myself, hi, my name is ... */ + if (verbose) + 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)) == 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); + } + + /* everybody needs these, don't they? */ + scan_dir("/usr/lib"); + } + + if (!nocache) + cache_write(); + } + + exit(EXIT_OK); +} + +typedef struct liblist +{ + int flags; + int sooffset; + int liboffset; + char *soname; + char *libname; + int skip; + 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(char *dir, char *so, char *lib, int libtype) +{ + char fullpath[PATH_MAX]; + liblist_t *new_lib, *cur_lib; + + magic.nlibs++; + sprintf(fullpath, "%s/%s", dir, lib); + new_lib = xmalloc(sizeof (liblist_t)); + new_lib->flags = libtype; + new_lib->soname = xstrdup(so); + new_lib->libname = xstrdup(fullpath); + new_lib->skip = 0; + + 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_rmlib(char *dir, char *so) +{ + char fullpath[PATH_MAX]; + liblist_t *cur_lib; + + sprintf(fullpath, "%s/%s", dir, so); + + for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next) + { + if (strcmp(cur_lib->soname, so) == 0 && + strcmp(cur_lib->libname, fullpath) == 0 && + !cur_lib->skip) + { + magic.nlibs--; + cur_lib->skip = 1; + } + } +} + +void cache_write(void) +{ + int cachefd; + int stroffset = 0; + char tempfile[1024]; + 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)); + + write(cachefd, &magic, sizeof (header_t)); + + for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next) + { + if (!cur_lib->skip) + { + cur_lib->sooffset = stroffset; + stroffset += strlen(cur_lib->soname) + 1; + cur_lib->liboffset = stroffset; + stroffset += strlen(cur_lib->libname) + 1; + write(cachefd, cur_lib, sizeof (libentry_t)); + } + } + + for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next) + { + if (!cur_lib->skip) + { + write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1); + write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1); + } + } + + close(cachefd); + + 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%2d - %s %s => %s\n", fd + 1, + libent[fd].flags == LIB_DLL ? "DLL" : "ELF", + strs + libent[fd].sooffset, + strs + libent[fd].liboffset); + } + + munmap (c,st.st_size); +} + diff --git a/gnu/libexec/ld.so/ldconfig/readelf.c b/gnu/libexec/ld.so/ldconfig/readelf.c new file mode 100644 index 00000000000..b15275e8daf --- /dev/null +++ b/gnu/libexec/ld.so/ldconfig/readelf.c @@ -0,0 +1,86 @@ +/* adapted from Eric Youngdale's readelf program */ + +#include +#include +#include +#include +#include + +char *xstrdup(char *); + +char *readsoname(FILE *infile) +{ + Elf32_Ehdr *epnt; + Elf32_Phdr *ppnt; + int i; + char *header; + unsigned int dynamic_addr = 0; + unsigned int dynamic_size = 0; + int strtab_val = 0; + int soname_val = 0; + int loadaddr = -1; + int loadbase = 0; + Elf32_Dyn *dpnt; + struct stat st; + char *res = NULL; + + 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 = (Elf32_Ehdr *)header; + if ((int)(epnt+1) > (int)(header + st.st_size)) + goto skip; + + ppnt = (Elf32_Phdr *)&header[epnt->e_phoff]; + if ((int)ppnt < (int)header || + (int)(ppnt+epnt->e_phnum) > (int)(header + st.st_size)) + goto skip; + + for(i = 0; i < epnt->e_phnum; i++) + { + if (loadaddr == -1 && ppnt->p_vaddr != 0) + loadaddr = (ppnt->p_vaddr & 0xfffff000) - + (ppnt->p_offset & 0xfffff000); + if(ppnt->p_type == 2) + { + dynamic_addr = ppnt->p_offset; + dynamic_size = ppnt->p_filesz; + }; + ppnt++; + }; + + dpnt = (Elf32_Dyn *) &header[dynamic_addr]; + dynamic_size = dynamic_size / sizeof(Elf32_Dyn); + if ((int)dpnt < (int)header || + (int)(dpnt+dynamic_size) > (int)(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; + if (dpnt->d_tag == DT_SONAME) + soname_val = dpnt->d_un.d_val; +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* XXX */ + if (dpnt->d_tag == DT_MIPS_BASE_ADDRESS) + loadbase = dpnt->d_un.d_val; + dpnt++; + }; + + if (!strtab_val || !soname_val) + goto skip; + if (soname_val + strtab_val - loadbase < 0 || + soname_val + strtab_val - loadbase >= st.st_size) + goto skip; + + res = xstrdup((char *) (header - loadbase + strtab_val + soname_val)); + + skip: + munmap(header, st.st_size); + + return res; +} + -- 2.20.1