summaryrefslogtreecommitdiff
path: root/ldso/ldso
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-04-23 17:43:54 +0000
committerEric Andersen <andersen@codepoet.org>2001-04-23 17:43:54 +0000
commit66f269d2a51dae6a2cb10f1a9ae4aaeba815219b (patch)
treee2094832990caf6d849ba90e4b1a82a6264f86b3 /ldso/ldso
parentc4a3f3f81ea90e3df93c352ac0e2161a4bfd3327 (diff)
Initial checkin for ld.so. This is a combination of effort from Manuel Novoa
III and me. I've been working on stripping out arch dependant stuff and replacing it with generic stuff whenever possible. -Erik
Diffstat (limited to 'ldso/ldso')
-rw-r--r--ldso/ldso/Makefile39
-rw-r--r--ldso/ldso/boot1.c1005
-rw-r--r--ldso/ldso/dl-elf.c588
-rw-r--r--ldso/ldso/dl-hash.c284
-rw-r--r--ldso/ldso/hash.c284
-rw-r--r--ldso/ldso/hash.h113
-rw-r--r--ldso/ldso/i386/dl-sysdep.h82
-rw-r--r--ldso/ldso/i386/elfinterp.c321
-rw-r--r--ldso/ldso/i386/ld_sysdep.h82
-rw-r--r--ldso/ldso/i386/resolve.S55
-rw-r--r--ldso/ldso/i386/sysdep.h82
-rw-r--r--ldso/ldso/ld-uClibc.c1005
-rw-r--r--ldso/ldso/ld_hash.h113
-rw-r--r--ldso/ldso/ld_string.h112
-rw-r--r--ldso/ldso/ld_syscall.h108
-rw-r--r--ldso/ldso/ldso.c1005
-rw-r--r--ldso/ldso/link.h37
-rw-r--r--ldso/ldso/linuxelf.h137
-rw-r--r--ldso/ldso/m68k/dl-sysdep.h87
-rw-r--r--ldso/ldso/m68k/elfinterp.c358
-rw-r--r--ldso/ldso/m68k/ld_sysdep.h87
-rw-r--r--ldso/ldso/m68k/resolve.S29
-rw-r--r--ldso/ldso/m68k/sysdep.h87
-rw-r--r--ldso/ldso/readelflib1.c588
-rw-r--r--ldso/ldso/sparc/DEFS.h5
-rw-r--r--ldso/ldso/sparc/dl-sysdep.h131
-rw-r--r--ldso/ldso/sparc/elfinterp.c355
-rw-r--r--ldso/ldso/sparc/ld_sysdep.h131
-rw-r--r--ldso/ldso/sparc/resolve.S25
-rw-r--r--ldso/ldso/sparc/sdiv.S369
-rw-r--r--ldso/ldso/sparc/sysdep.h131
-rw-r--r--ldso/ldso/sparc/udiv.S351
-rw-r--r--ldso/ldso/sparc/umul.S153
-rw-r--r--ldso/ldso/sparc/urem.S352
-rw-r--r--ldso/ldso/string.h112
-rw-r--r--ldso/ldso/syscall.h108
-rw-r--r--ldso/ldso/vsprintf.c290
37 files changed, 9201 insertions, 0 deletions
diff --git a/ldso/ldso/Makefile b/ldso/ldso/Makefile
new file mode 100644
index 000000000..80f0643ea
--- /dev/null
+++ b/ldso/ldso/Makefile
@@ -0,0 +1,39 @@
+TOPDIR=../../
+include $(TOPDIR)Rules.mak
+include $(TOPDIR)/ld.so-1/Config.mk
+
+DIRS = $(TARGET_ARCH) libdl
+
+CFLAGS += -DNO_UNDERSCORE -DVERBOSE_DLINKER
+CFLAGS += -DUSE_CACHE #-fPIC -D__PIC__ #-funroll-loops
+
+CSRC= boot1.c hash.c readelflib1.c vsprintf.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+OBJS=$(COBJS)
+
+DLINKER = ld-linux-uclibc.so
+
+ELF_LDFLAGS=--shared # using GNU ld
+
+ifneq ($(DIRS),)
+lib realclean clean::
+ @set -e; for i in $(DIRS); do \
+ echo making $@ in $$i; \
+ $(MAKE) -C $$i $@; \
+ done;
+endif
+
+lib:: $(OBJS)
+ $(LD) -e _dl_boot $(ELF_LDFLAGS) -o $(DLINKER).$(LDSO_VMAJOR) \
+ -soname $(DLINKER).$(LDSO_VMAJOR) *.o
+
+$(COBJS): %.o : %.c
+ $(CC) -I. -I./$(TARGET_ARCH) $(CFLAGS) -c $< -o $@
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+realclean::
+ $(RM) -f .depend $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~
+
+clean::
+ $(RM) -f $(DLINKER) core *.o *.a *.s *.i tmp_make foo *~
+
diff --git a/ldso/ldso/boot1.c b/ldso/ldso/boot1.c
new file mode 100644
index 000000000..6b0b864cb
--- /dev/null
+++ b/ldso/ldso/boot1.c
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* 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 <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+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-linux-uclibc.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);
+
+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 int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct 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.
+ */
+void _dl_debug_state()
+{
+ return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+ unsigned int argc;
+ char ** argv, ** envp;
+ int status;
+
+ unsigned int load_addr;
+ unsigned int * got;
+ unsigned int * aux_dat;
+ int goof = 0;
+ struct elfhdr * header;
+ struct elf_resolve * tpnt;
+ struct dyn_elf * rpnt;
+ struct elf_resolve * app_tpnt;
+ unsigned int brk_addr;
+ unsigned int dl_data[AT_EGID+1];
+ unsigned char * malloc_buffer, *mmap_zero;
+ int (*_dl_atexit)(void *);
+ int * lpnt;
+ struct dynamic * dpnt;
+ unsigned int *hash_addr;
+ struct r_debug * debug_addr;
+ unsigned int *chains;
+ int indx;
+ int _dl_secure;
+
+ /* First obtain the information on the stack that tells us more about
+ what binary is loaded, where it is loaded, etc, etc */
+
+ GET_ARGV(aux_dat, args);
+ argc = *(aux_dat - 1);
+ argv = (char **) aux_dat;
+ aux_dat += argc; /* Skip over the argv pointers */
+ aux_dat++; /* Skip over NULL at end of argv */
+ envp = (char **) aux_dat;
+ while(*aux_dat) aux_dat++; /* Skip over the envp pointers */
+ aux_dat++; /* Skip over NULL at end of envp */
+ dl_data[AT_UID] = -1; /* check later to see if it is changed */
+ while(*aux_dat)
+ {
+ unsigned int * ad1;
+ ad1 = aux_dat + 1;
+ if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+ aux_dat += 2;
+ }
+
+ /* Next, locate the GOT */
+
+ load_addr = dl_data[AT_BASE];
+
+ GET_GOT(got);
+ dpnt = (struct dynamic *) (*got + 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. */
+
+ {
+ /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+ int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+ /* See if we need to relocate this address */
+ mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+ if(_dl_mmap_check_error(mmap_zero)) {
+ SEND_STDERR("dl_boot: mmap of /dev/zero 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)
+ {
+ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+ dpnt++;
+ }
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+ if(ppnt->p_type == PT_DYNAMIC) {
+ dpnt = (struct dynamic *) ppnt->p_vaddr;
+ while(dpnt->d_tag)
+ {
+ if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+ app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) 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;
+
+ /* Ugly, ugly. We need to call mprotect to change the protection of
+ the text pages so that we can do the dynamic linking. We can set the
+ protection back again once we are done */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ /* First cover the shared library/dynamic linker. */
+ if(tpnt->dynamic_info[DT_TEXTREL]) {
+ header = (struct elfhdr *) dl_data[AT_BASE];
+ ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+ for(i=0; i<header->e_phnum ; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+
+ /* Now cover the application program. */
+ if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+ }
+
+ /* 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;
+
+
+#ifdef ELF_USES_RELOCA
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+ if(!rel_addr) continue;
+
+ /* Now parse the relocation information */
+ rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+ for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+ reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ if(symtab_index) {
+ char * strtab;
+ struct elf32_sym * symtab;
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+ /* We only do a partial dynamic linking right now. The user
+ is not supposed to redefine any symbols that start with
+ a '_', so we can do this with confidence. */
+
+ if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+ symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+ if(!symbol_addr) {
+ /*
+ * This will segfault - you cannot call a function until
+ * we have finished the relocations.
+ */
+ SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+ SEND_STDERR(strtab + symtab[symtab_index].st_name);
+ SEND_STDERR(" undefined.\n");
+ goof++;
+ }
+ }
+ /*
+ * Use this machine-specific macro to perform the actual relocation.
+ */
+ PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+ }
+ }
+
+ if (goof) _dl_exit(14);
+
+ /* 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);
+ INIT_GOT(lpnt, tpnt);
+
+ /* 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;
+
+ { struct elfhdr * epnt;
+ struct elf_phdr * ppnt;
+ int i;
+
+ epnt = (struct elfhdr *) dl_data[AT_BASE];
+ tpnt->n_phent = epnt->e_phnum;
+ tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + 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;
+
+ 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 */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD) {
+ if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr)
+ brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+ }
+ if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+ /* make sure it's really there. */
+ if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+ /* OK, we have what we need - slip this one into the list. */
+ app_tpnt = _dl_add_elf_hash_table("", 0,
+ app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+ _dl_loaded_modules->libtype = elf_executable;
+ _dl_loaded_modules->ppnt = (struct elf_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]);
+#ifdef ALLOW_ZERO_PLTGOT
+ if (lpnt)
+#endif
+ INIT_GOT(lpnt, _dl_loaded_modules);
+ }
+ if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+ this before */
+ tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+ }
+ }
+ }
+
+ 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);
+
+ if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+ (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+ dl_data[AT_GID] == dl_data[AT_EGID]))
+ {
+ _dl_secure = 0;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+ }
+ else
+ {
+ _dl_secure = 1;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+ _dl_unsetenv("LD_LIBRARY_PATH", envp);
+ _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+ _dl_library_path = NULL;
+ }
+ }
+
+ _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;
+
+ if (_dl_preload) {
+ char c, *str, *str2;
+
+ str = _dl_preload;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ while (*str) {
+ str2 = str;
+ while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+ str2++;
+ c = *str2;
+ *str2 = '\0';
+ if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+ tpnt1 = _dl_load_shared_library(_dl_secure, NULL, 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) {
+ /* this is a real hack to make ldd not print the
+ library itself when run on a library. */
+ if (_dl_strcmp(_dl_progname, str) != 0)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ }
+ 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;
+ }
+ }
+ *str2 = c;
+ str = str2;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ }
+ }
+
+ {
+ int fd;
+ struct kernel_stat st;
+ char *preload;
+
+ if (!_dl_stat(LDSO_PRELOAD, &st)) {
+ if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+ _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ _dl_close (fd);
+ if (preload == (caddr_t)-1) {
+ _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ char c, *cp, *cp2;
+
+ /* convert all separators and comments to spaces */
+ for (cp = preload; *cp; /*nada*/) {
+ if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+ *cp++ = ' ';
+ } else if (*cp == '#') {
+ do
+ *cp++ = ' ';
+ while (*cp != '\n' && *cp != '\0');
+ } else {
+ cp++;
+ }
+ }
+
+ /* find start of first library */
+ for (cp = preload; *cp && *cp == ' '; cp++)
+ /*nada*/;
+
+ while (*cp) {
+ /* find end of library */
+ for (cp2 = cp; *cp && *cp != ' '; cp++)
+ /*nada*/;
+ c = *cp;
+ *cp = '\0';
+
+ tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+ if (!tpnt1) {
+ if (_dl_trace_loaded_objects)
+ _dl_fdprintf(1, "\t%s => not found\n", cp2);
+ else {
+ _dl_fdprintf(2, "%s: can't load library '%s'\n",
+ _dl_progname, cp2);
+ _dl_exit(15);
+ }
+ } else {
+ if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+
+ /* find start of next library */
+ *cp = c;
+ for (/*nada*/; *cp && *cp == ' '; cp++)
+ /*nada*/;
+ }
+
+ _dl_munmap(preload, st.st_size+1);
+ }
+ }
+ }
+ }
+
+ for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+ {
+ for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+ {
+ if(dpnt->d_tag == DT_NEEDED)
+ {
+ lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+ dpnt->d_un.d_val;
+ if (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(0, tcurr, 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 (0x%x)\n", lpnt, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+#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_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+ /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+ and we have to manually search for entries that require fixups.
+ Solaris gets this one right, from what I understand. */
+
+
+ if (_dl_symbol_tables)
+ goof += _dl_copy_fixups(_dl_symbol_tables);
+
+ 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;
+
+ {
+ int i;
+ struct elf_phdr * ppnt;
+
+ /* We had to set the protections of all pages to R/W for dynamic linking.
+ Set text pages back to R/O */
+ for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+ for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+ tpnt->dynamic_info[DT_TEXTREL])
+ _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags));
+
+ }
+
+ _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+ /*
+ * 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;
+ debug_addr->r_state = RT_CONSISTENT;
+ /* This is written in this funny way to keep gcc from inlining the
+ function call. */
+ ((void (*)(void))debug_addr->r_brk)();
+
+ 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 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]) {
+#ifdef ELF_USES_RELOCA
+ _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+ _dl_exit(17);
+#else
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+ tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+ }
+ if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+ tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+ _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+ _dl_exit(18);
+#endif
+ }
+ 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)
+ _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ else
+ goof += _dl_parse_relocation_information(tpnt,
+ tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ }
+ return goof;
+}
+
+void * _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_PRIVATE | MAP_ANONYMOUS, -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 && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if (!*pnt || *pnt != '=' || *pnt1)
+ continue;
+ return pnt+1;
+ }
+ return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+ char *pnt;
+ char *pnt1;
+ char **newenvp = envp;
+ for (pnt = *envp; pnt; pnt = *++envp) {
+ pnt1 = symbol;
+ while (*pnt && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if(!*pnt || *pnt != '=' || *pnt1)
+ *newenvp++ = *envp;
+ }
+ *newenvp++ = *envp;
+ return;
+}
+
+char * _dl_strdup(const char * string){
+ char * retval;
+ int len;
+
+ len = _dl_strlen(string);
+ retval = _dl_malloc(len + 1);
+ _dl_strcpy(retval, string);
+ return retval;
+}
+
+/* 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;
+}
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
new file mode 100644
index 000000000..9d1cd0ff5
--- /dev/null
+++ b/ldso/ldso/dl-elf.c
@@ -0,0 +1,588 @@
+/* Load an ELF sharable library into memory.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* This file contains the helper routines to load an ELF sharable
+ library into memory and add the symbol table info to the chain. */
+
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "string.h"
+/*#include <stdlib.h>*/
+#include <linux/mman.h>
+#include <linux/stat.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+#ifdef USE_CACHE
+#include "../config.h"
+#endif
+
+extern char *_dl_progname;
+
+#ifdef USE_CACHE
+
+static caddr_t _dl_cache_addr = NULL;
+static size_t _dl_cache_size = 0;
+
+int _dl_map_cache(void)
+{
+ int fd;
+ struct kernel_stat st;
+ header_t *header;
+ libentry_t *libent;
+ int i, strtabsize;
+
+ if (_dl_cache_addr == (caddr_t)-1)
+ return -1;
+ else if (_dl_cache_addr != NULL)
+ return 0;
+
+ if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
+ {
+ _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
+ _dl_cache_addr = (caddr_t)-1; /* so we won't try again */
+ return -1;
+ }
+
+ _dl_cache_size = st.st_size;
+ _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
+ MAP_SHARED, fd, 0);
+ _dl_close (fd);
+ if (_dl_cache_addr == (caddr_t)-1)
+ {
+ _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
+ return -1;
+ }
+
+ header = (header_t *)_dl_cache_addr;
+
+ if (_dl_cache_size < sizeof (header_t) ||
+ _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
+ _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
+ _dl_cache_size <
+ (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
+ _dl_cache_addr[_dl_cache_size-1] != '\0')
+ {
+ _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+ goto fail;
+ }
+
+ strtabsize = _dl_cache_size - sizeof (header_t) -
+ header->nlibs * sizeof (libentry_t);
+ libent = (libentry_t *)&header[1];
+
+ for (i = 0; i < header->nlibs; i++)
+ {
+ if (libent[i].sooffset >= strtabsize ||
+ libent[i].liboffset >= strtabsize)
+ {
+ _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ _dl_munmap(_dl_cache_addr, _dl_cache_size);
+ _dl_cache_addr = (caddr_t)-1;
+ return -1;
+}
+
+int _dl_unmap_cache(void)
+{
+ if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
+ return -1;
+
+#if 1
+ _dl_munmap (_dl_cache_addr, _dl_cache_size);
+ _dl_cache_addr = NULL;
+#endif
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Used to return error codes back to dlopen et. al.
+ */
+
+unsigned int _dl_error_number;
+unsigned int _dl_internal_error_number;
+
+struct elf_resolve * _dl_load_shared_library(int secure,
+ struct elf_resolve * tpnt, char * full_libname) {
+ char * pnt, *pnt1, *pnt2;
+ struct elf_resolve *tpnt1 = NULL;
+ char mylibname[2050];
+ char * libname;
+
+ _dl_internal_error_number = 0;
+
+ /* quick hack to ensure mylibname buffer doesn't overflow. don't
+ allow full_libname or any directory to be longer than 1024. */
+ if (_dl_strlen(full_libname) > 1024)
+ goto goof;
+
+ pnt = libname = full_libname;
+ while (*pnt) {
+ if(*pnt == '/') libname = pnt+1;
+ pnt++;
+ }
+
+ /* If the filename has any '/', try it straight and leave it at that.
+ For IBCS2 compatibility under linux, we substitute the string
+ /usr/i486-sysv4/lib for /usr/lib in library names. */
+
+ if (libname != full_libname) {
+ tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
+ if (tpnt1)
+ return tpnt1;
+ goto goof;
+ }
+
+ /*
+ * The ABI specifies that RPATH is searched before LD_*_PATH or
+ * the default path of /usr/lib.
+ * Check in rpath directories
+ */
+ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+ if (tpnt->libtype == elf_executable) {
+ pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
+ if(pnt1) {
+ pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
+ while(*pnt1){
+ pnt2 = mylibname;
+ while(*pnt1 && *pnt1 != ':') {
+ if (pnt2 - mylibname < 1024)
+ *pnt2++ = *pnt1++;
+ else
+ pnt1++;
+ }
+ if (pnt2 - mylibname >= 1024)
+ break;
+ if(pnt2[-1] != '/') *pnt2++ = '/';
+ pnt = libname;
+ while(*pnt) *pnt2++ = *pnt++;
+ *pnt2++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if(tpnt1) return tpnt1;
+ if(*pnt1 == ':') pnt1++;
+ }
+ }
+ }
+ }
+
+
+ /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
+ pnt1 = _dl_library_path;
+ if (pnt1 && *pnt1) {
+ while (*pnt1) {
+ pnt2 = mylibname;
+ while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
+ if (pnt2 - mylibname < 1024)
+ *pnt2++ = *pnt1++;
+ else
+ pnt1++;
+ }
+ if (pnt2 - mylibname >= 1024)
+ break;
+ if(pnt2[-1] != '/') *pnt2++ = '/';
+ pnt = libname;
+ while(*pnt) *pnt2++ = *pnt++;
+ *pnt2++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if(tpnt1) return tpnt1;
+ if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
+ }
+ }
+
+
+ /*
+ * Where should the cache be searched? There is no such concept in the
+ * ABI, so we have some flexibility here. For now, search it before
+ * the default path of /usr/lib.
+ */
+#ifdef USE_CACHE
+ if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
+ {
+ int i;
+ header_t *header = (header_t *)_dl_cache_addr;
+ libentry_t *libent = (libentry_t *)&header[1];
+ char *strs = (char *)&libent[header->nlibs];
+
+ for (i = 0; i < header->nlibs; i++)
+ {
+ if ((libent[i].flags == LIB_ELF ||
+ libent[i].flags == LIB_ELF_LIBC5) &&
+ _dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
+ (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
+ return tpnt1;
+ }
+ }
+#endif
+
+
+#ifdef UCLIBC_DEVEL
+
+ /* Check in /usr/<arch>-linux-uclibc/lib */
+ pnt1 = UCLIBC_INSTALL_DIR"/lib";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+
+#else /* UCLIBC_DEVEL */
+
+ /* Check in /usr/lib */
+ pnt1 = "/usr/lib/";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+
+ /* Check in /lib */
+ /* try "/lib/". */
+ pnt1 = "/lib/";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+#endif /* UCLIBC_DEVEL */
+
+goof:
+ /* Well, we shot our wad on that one. All we can do now is punt */
+ if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
+ else _dl_error_number = DL_ERROR_NOFILE;
+ return NULL;
+}
+
+/*
+ * Read one ELF library into memory, mmap it into the correct locations and
+ * add the symbol info to the symbol chain. Perform any relocations that
+ * are required.
+ */
+
+//extern _elf_rtbndr(void);
+
+struct elf_resolve * _dl_load_elf_shared_library(int secure,
+ char * libname, int flag) {
+ struct elfhdr * epnt;
+ unsigned int dynamic_addr = 0;
+ unsigned int dynamic_size = 0;
+ struct dynamic * dpnt;
+ struct elf_resolve * tpnt;
+ struct elf_phdr * ppnt;
+ int piclib;
+ char * status;
+ int flags;
+ char header[4096];
+ int dynamic_info[24];
+ int * lpnt;
+ unsigned int libaddr;
+ unsigned int minvma=0xffffffff, maxvma=0;
+
+ int i;
+ int infile;
+
+ /* If this file is already loaded, skip this step */
+ tpnt = _dl_check_hashed_files(libname);
+ if(tpnt) return tpnt;
+
+ /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
+ we don't load the library if it isn't setuid. */
+
+ if (secure) {
+ struct kernel_stat st;
+ if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
+ return NULL;
+ }
+
+ libaddr = 0;
+ infile = _dl_open(libname, O_RDONLY);
+ if(infile < 0)
+ {
+#if 0
+ /*
+ * NO! When we open shared libraries we may search several paths.
+ * it is inappropriate to generate an error here.
+ */
+ _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
+#endif
+ _dl_internal_error_number = DL_ERROR_NOFILE;
+ return NULL;
+ }
+
+ _dl_read(infile, header, sizeof(header));
+ epnt = (struct elfhdr *) header;
+ if (epnt->e_ident[0] != 0x7f ||
+ epnt->e_ident[1] != 'E' ||
+ epnt->e_ident[2] != 'L' ||
+ epnt->e_ident[3] != 'F') {
+ _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_NOTELF;
+ _dl_close(infile);
+ return NULL;
+ };
+
+ if((epnt->e_type != ET_DYN) ||
+ (epnt->e_machine != MAGIC1
+#ifdef MAGIC2
+ && epnt->e_machine != MAGIC2
+#endif
+ )){
+ _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
+ _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
+ _dl_progname, libname);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+ piclib = 1;
+ for(i=0;i < epnt->e_phnum; i++){
+
+ if(ppnt->p_type == PT_DYNAMIC) {
+ if (dynamic_addr)
+ _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
+ _dl_progname, libname);
+ dynamic_addr = ppnt->p_vaddr;
+ dynamic_size = ppnt->p_filesz;
+ };
+
+ if(ppnt->p_type == PT_LOAD) {
+ /* See if this is a PIC library. */
+ if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+ piclib = 0;
+ minvma=ppnt->p_vaddr;
+ }
+ if(piclib && ppnt->p_vaddr < minvma) {
+ minvma = ppnt->p_vaddr;
+ }
+ if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
+ maxvma = ppnt->p_vaddr + ppnt->p_memsz;
+ }
+ }
+ ppnt++;
+ };
+
+ maxvma=(maxvma+0xfffU)&~0xfffU;
+ minvma=minvma&~0xffffU;
+
+ flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
+ if(!piclib) flags |= MAP_FIXED;
+
+ status = (char *) _dl_mmap((char *) (piclib?0:minvma),
+ maxvma-minvma,
+ PROT_NONE,
+ flags | MAP_ANONYMOUS, -1,
+ 0);
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_close(infile);
+ return NULL;
+ };
+ libaddr=(unsigned int)status;
+ flags|=MAP_FIXED;
+
+ /* Get the memory to store the library */
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+ for(i=0;i < epnt->e_phnum; i++){
+ if(ppnt->p_type == PT_LOAD) {
+
+ /* See if this is a PIC library. */
+ if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+ piclib = 0;
+ /* flags |= MAP_FIXED; */
+ }
+
+
+
+ if(ppnt->p_flags & PF_W) {
+ unsigned int map_size;
+ char * cpnt;
+
+ status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) +
+ (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags),
+ flags, infile,
+ ppnt->p_offset & 0x7ffff000);
+
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_munmap((char *)libaddr, maxvma-minvma);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ /* Pad the last page with zeroes. */
+ cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
+ while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
+
+/* I am not quite sure if this is completely correct to do or not, but
+ the basic way that we handle bss segments is that we mmap /dev/zero if
+ there are any pages left over that are not mapped as part of the file */
+
+ map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
+ if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
+ status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0),
+ ppnt->p_vaddr + ppnt->p_memsz - map_size,
+ LXFLAGS(ppnt->p_flags),
+ flags | MAP_ANONYMOUS, -1, 0);
+ } else
+ status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) +
+ (piclib?libaddr:0),
+ (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags),
+ flags, infile,
+ ppnt->p_offset & 0x7ffff000);
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_munmap((char *)libaddr, maxvma-minvma);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ /* if(libaddr == 0 && piclib) {
+ libaddr = (unsigned int) status;
+ flags |= MAP_FIXED;
+ }; */
+ };
+ ppnt++;
+ };
+ _dl_close(infile);
+
+ /* For a non-PIC library, the addresses are all absolute */
+ if(piclib) {
+ dynamic_addr += (unsigned int) libaddr;
+ }
+
+ /*
+ * OK, the ELF library is now loaded into VM in the correct locations
+ * The next step is to go through and do the dynamic linking (if needed).
+ */
+
+ /* Start by scanning the dynamic section to get all of the pointers */
+
+ if(!dynamic_addr) {
+ _dl_internal_error_number = DL_ERROR_NODYNAMIC;
+ _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
+ return NULL;
+ }
+
+ dpnt = (struct dynamic *) dynamic_addr;
+
+ dynamic_size = dynamic_size / sizeof(struct dynamic);
+ _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
+ for(i=0; i< dynamic_size; i++){
+ if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
+ dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
+ dpnt++;
+ };
+
+ /* If the TEXTREL is set, this means that we need to make the pages
+ writable before we perform relocations. Do this now. They get set back
+ again later. */
+
+ if (dynamic_info[DT_TEXTREL]) {
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+ for(i=0;i < epnt->e_phnum; i++, ppnt++){
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+
+
+ tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr,
+ dynamic_size);
+
+ tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
+ tpnt->n_phent = epnt->e_phnum;
+
+ /*
+ * OK, the next thing we need to do is to insert the dynamic linker into
+ * the proper entry in the GOT so that the PLT symbols can be properly
+ * resolved.
+ */
+
+ lpnt = (int *) dynamic_info[DT_PLTGOT];
+
+ if(lpnt) {
+ lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
+ INIT_GOT(lpnt, tpnt);
+ };
+
+ return tpnt;
+}
+
+/* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY
+ relocations for global variables that are present both in the image and
+ the shared library. Go through and do it manually. If the images
+ are guaranteed to be generated by a trustworthy linker, then this
+ step can be skipped. */
+
+int _dl_copy_fixups(struct dyn_elf * rpnt)
+{
+ int goof = 0;
+ struct elf_resolve * tpnt;
+
+ if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
+ else return 0;
+
+ tpnt = rpnt->dyn;
+
+ if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
+ tpnt->init_flag |= COPY_RELOCS_DONE;
+
+#ifdef ELF_USES_RELOCA
+ goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
+ tpnt->dynamic_info[DT_RELASZ], 0);
+
+#else
+ goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
+ tpnt->dynamic_info[DT_RELSZ], 0);
+
+#endif
+ return goof;
+}
+
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
new file mode 100644
index 000000000..4eab974a8
--- /dev/null
+++ b/ldso/ldso/dl-hash.c
@@ -0,0 +1,284 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* Various symbol table handling functions, including symbol lookup */
+
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/elf.h>
+
+#include "libdl/dlfcn.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+#include "sysdep.h"
+
+/*
+ * This is the start of the linked list that describes all of the files present
+ * in the system with pointers to all of the symbol, string, and hash tables,
+ * as well as all of the other good stuff in the binary.
+ */
+
+struct elf_resolve * _dl_loaded_modules = NULL;
+
+/*
+ * This is the list of modules that are loaded when the image is first
+ * started. As we add more via dlopen, they get added into other
+ * chains.
+ */
+struct dyn_elf * _dl_symbol_tables = NULL;
+
+/*
+ * This is the list of modules that are loaded via dlopen. We may need
+ * to search these for RTLD_GLOBAL files.
+ */
+struct dyn_elf * _dl_handles = NULL;
+
+
+/*
+ * This is the hash function that is used by the ELF linker to generate
+ * the hash table that each executable and library is required to
+ * have. We need it to decode the hash table.
+ */
+
+unsigned long _dl_elf_hash(const char * name){
+ unsigned long hash = 0;
+ unsigned long tmp;
+
+ while (*name){
+ hash = (hash << 4) + *name++;
+ if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
+ hash &= ~tmp;
+ };
+ return hash;
+}
+
+/*
+ * Check to see if a library has already been added to the hash chain.
+ */
+struct elf_resolve * _dl_check_hashed_files(char * libname){
+ struct elf_resolve * tpnt;
+ int len = _dl_strlen(libname);
+
+ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+ if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
+ (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
+ return tpnt;
+ }
+
+ return NULL;
+}
+
+/*
+ * We call this function when we have just read an ELF library or executable.
+ * We add the relevant info to the symbol chain, so that we can resolve all
+ * externals properly.
+ */
+
+struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+ char * loadaddr,
+ unsigned int * dynamic_info,
+ unsigned int dynamic_addr,
+ unsigned int dynamic_size){
+ unsigned int * hash_addr;
+ struct elf_resolve * tpnt;
+ int i;
+
+ if (!_dl_loaded_modules) {
+ tpnt = _dl_loaded_modules =
+ (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+ _dl_memset (tpnt, 0, sizeof (*tpnt));
+ }
+ else {
+ tpnt = _dl_loaded_modules;
+ while(tpnt->next) tpnt = tpnt->next;
+ tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+ _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
+ tpnt->next->prev = tpnt;
+ tpnt = tpnt->next;
+ };
+
+ tpnt->next = NULL;
+ tpnt->init_flag = 0;
+ tpnt->libname = _dl_strdup(libname);
+ tpnt->dynamic_addr = dynamic_addr;
+ tpnt->dynamic_size = dynamic_size;
+ tpnt->libtype = loaded_file;
+
+ if( dynamic_info[DT_HASH] != 0 )
+ {
+ hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
+ tpnt->nbucket = *hash_addr++;
+ tpnt->nchain = *hash_addr++;
+ tpnt->elf_buckets = hash_addr;
+ hash_addr += tpnt->nbucket;
+ tpnt->chains = hash_addr;
+ }
+ tpnt->loadaddr = loadaddr;
+ for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
+ return tpnt;
+}
+
+
+/*
+ * This function resolves externals, and this is either called when we process
+ * relocations or when we call an entry in the PLT table for the first time.
+ */
+
+char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
+ unsigned int instr_addr, struct elf_resolve * f_tpnt,
+ int copyrel){
+ struct elf_resolve * tpnt;
+ int si;
+ char * pnt;
+ int pass;
+ char * strtab;
+ struct elf32_sym * symtab;
+ unsigned int elf_hash_number, hn;
+ char * weak_result;
+ struct elf_resolve * first_def;
+ struct dyn_elf * rpnt, first;
+ char * data_result = 0; /* nakao */
+
+ weak_result = 0;
+ elf_hash_number = _dl_elf_hash(name);
+
+ /* A quick little hack to make sure that any symbol in the executable
+ will be preferred to one in a shared library. This is necessary so
+ that any shared library data symbols referenced in the executable
+ will be seen at the same address by the executable, shared libraries
+ and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
+ if(!copyrel && rpnt1) {
+ first=(*_dl_symbol_tables);
+ first.next=rpnt1;
+ rpnt1=(&first);
+ }
+
+ /*
+ * The passes are so that we can first search the regular symbols
+ * for whatever module was specified, and then search anything
+ * loaded with RTLD_GLOBAL. When pass is 1, it means we are just
+ * starting the first dlopened module, and anything above that
+ * is just the next one in the chain.
+ */
+ for(pass = 0; (1==1); pass++)
+ {
+
+ /*
+ * If we are just starting to search for RTLD_GLOBAL, setup
+ * the pointer for the start of the search.
+ */
+ if( pass == 1) {
+ rpnt1 = _dl_handles;
+ }
+
+ /*
+ * Anything after this, we need to skip to the next module.
+ */
+ else if( pass >= 2) {
+ rpnt1 = rpnt1->next_handle;
+ }
+
+ /*
+ * Make sure we still have a module, and make sure that this
+ * module was loaded with RTLD_GLOBAL.
+ */
+ if( pass != 0 )
+ {
+ if( rpnt1 == NULL ) break;
+ if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
+ }
+
+ for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables);
+ rpnt; rpnt = rpnt->next) {
+ tpnt = rpnt->dyn;
+
+ /*
+ * The idea here is that if we are using dlsym, we want to
+ * first search the entire chain loaded from dlopen, and
+ * return a result from that if we found anything. If this
+ * fails, then we continue the search into the stuff loaded
+ * when the image was activated. For normal lookups, we start
+ * with rpnt == NULL, so we should never hit this.
+ */
+ if( tpnt->libtype == elf_executable
+ && weak_result != 0 )
+ {
+ break;
+ }
+
+ /*
+ * Avoid calling .urem here.
+ */
+ do_rem(hn, elf_hash_number, tpnt->nbucket);
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] +
+ tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+ /*
+ * This crap is required because the first instance of a
+ * symbol on the chain will be used for all symbol references.
+ * Thus this instance must be resolved to an address that
+ * contains the actual function,
+ */
+
+ first_def = NULL;
+
+ for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
+ pnt = strtab + symtab[si].st_name;
+
+ if(_dl_strcmp(pnt, name) == 0 &&
+ (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
+ ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
+ ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
+ symtab[si].st_value != 0) {
+
+ /* Here we make sure that we find a module where the symbol is
+ * actually defined.
+ */
+
+ if(f_tpnt) {
+ if(!first_def) first_def = tpnt;
+ if(first_def == f_tpnt && symtab[si].st_shndx == 0)
+ continue;
+ }
+
+ switch(ELF32_ST_BIND(symtab[si].st_info)){
+ case STB_GLOBAL:
+ if ( tpnt->libtype != elf_executable
+ && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
+ data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
+ break; /* nakao */
+ } else /* nakao */
+ return tpnt->loadaddr + symtab[si].st_value;
+ case STB_WEAK:
+ if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
+ break;
+ default: /* Do local symbols need to be examined? */
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (data_result) return data_result; /* nakao */
+ return weak_result;
+}
diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c
new file mode 100644
index 000000000..4eab974a8
--- /dev/null
+++ b/ldso/ldso/hash.c
@@ -0,0 +1,284 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* Various symbol table handling functions, including symbol lookup */
+
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/elf.h>
+
+#include "libdl/dlfcn.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+#include "sysdep.h"
+
+/*
+ * This is the start of the linked list that describes all of the files present
+ * in the system with pointers to all of the symbol, string, and hash tables,
+ * as well as all of the other good stuff in the binary.
+ */
+
+struct elf_resolve * _dl_loaded_modules = NULL;
+
+/*
+ * This is the list of modules that are loaded when the image is first
+ * started. As we add more via dlopen, they get added into other
+ * chains.
+ */
+struct dyn_elf * _dl_symbol_tables = NULL;
+
+/*
+ * This is the list of modules that are loaded via dlopen. We may need
+ * to search these for RTLD_GLOBAL files.
+ */
+struct dyn_elf * _dl_handles = NULL;
+
+
+/*
+ * This is the hash function that is used by the ELF linker to generate
+ * the hash table that each executable and library is required to
+ * have. We need it to decode the hash table.
+ */
+
+unsigned long _dl_elf_hash(const char * name){
+ unsigned long hash = 0;
+ unsigned long tmp;
+
+ while (*name){
+ hash = (hash << 4) + *name++;
+ if((tmp = hash & 0xf0000000)) hash ^= tmp >> 24;
+ hash &= ~tmp;
+ };
+ return hash;
+}
+
+/*
+ * Check to see if a library has already been added to the hash chain.
+ */
+struct elf_resolve * _dl_check_hashed_files(char * libname){
+ struct elf_resolve * tpnt;
+ int len = _dl_strlen(libname);
+
+ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+ if (_dl_strncmp(tpnt->libname, libname, len) == 0 &&
+ (tpnt->libname[len] == '\0' || tpnt->libname[len] == '.'))
+ return tpnt;
+ }
+
+ return NULL;
+}
+
+/*
+ * We call this function when we have just read an ELF library or executable.
+ * We add the relevant info to the symbol chain, so that we can resolve all
+ * externals properly.
+ */
+
+struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+ char * loadaddr,
+ unsigned int * dynamic_info,
+ unsigned int dynamic_addr,
+ unsigned int dynamic_size){
+ unsigned int * hash_addr;
+ struct elf_resolve * tpnt;
+ int i;
+
+ if (!_dl_loaded_modules) {
+ tpnt = _dl_loaded_modules =
+ (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+ _dl_memset (tpnt, 0, sizeof (*tpnt));
+ }
+ else {
+ tpnt = _dl_loaded_modules;
+ while(tpnt->next) tpnt = tpnt->next;
+ tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+ _dl_memset (tpnt->next, 0, sizeof (*(tpnt->next)));
+ tpnt->next->prev = tpnt;
+ tpnt = tpnt->next;
+ };
+
+ tpnt->next = NULL;
+ tpnt->init_flag = 0;
+ tpnt->libname = _dl_strdup(libname);
+ tpnt->dynamic_addr = dynamic_addr;
+ tpnt->dynamic_size = dynamic_size;
+ tpnt->libtype = loaded_file;
+
+ if( dynamic_info[DT_HASH] != 0 )
+ {
+ hash_addr = (unsigned int *) (dynamic_info[DT_HASH] + loadaddr);
+ tpnt->nbucket = *hash_addr++;
+ tpnt->nchain = *hash_addr++;
+ tpnt->elf_buckets = hash_addr;
+ hash_addr += tpnt->nbucket;
+ tpnt->chains = hash_addr;
+ }
+ tpnt->loadaddr = loadaddr;
+ for(i=0; i<24; i++) tpnt->dynamic_info[i] = dynamic_info[i];
+ return tpnt;
+}
+
+
+/*
+ * This function resolves externals, and this is either called when we process
+ * relocations or when we call an entry in the PLT table for the first time.
+ */
+
+char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
+ unsigned int instr_addr, struct elf_resolve * f_tpnt,
+ int copyrel){
+ struct elf_resolve * tpnt;
+ int si;
+ char * pnt;
+ int pass;
+ char * strtab;
+ struct elf32_sym * symtab;
+ unsigned int elf_hash_number, hn;
+ char * weak_result;
+ struct elf_resolve * first_def;
+ struct dyn_elf * rpnt, first;
+ char * data_result = 0; /* nakao */
+
+ weak_result = 0;
+ elf_hash_number = _dl_elf_hash(name);
+
+ /* A quick little hack to make sure that any symbol in the executable
+ will be preferred to one in a shared library. This is necessary so
+ that any shared library data symbols referenced in the executable
+ will be seen at the same address by the executable, shared libraries
+ and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
+ if(!copyrel && rpnt1) {
+ first=(*_dl_symbol_tables);
+ first.next=rpnt1;
+ rpnt1=(&first);
+ }
+
+ /*
+ * The passes are so that we can first search the regular symbols
+ * for whatever module was specified, and then search anything
+ * loaded with RTLD_GLOBAL. When pass is 1, it means we are just
+ * starting the first dlopened module, and anything above that
+ * is just the next one in the chain.
+ */
+ for(pass = 0; (1==1); pass++)
+ {
+
+ /*
+ * If we are just starting to search for RTLD_GLOBAL, setup
+ * the pointer for the start of the search.
+ */
+ if( pass == 1) {
+ rpnt1 = _dl_handles;
+ }
+
+ /*
+ * Anything after this, we need to skip to the next module.
+ */
+ else if( pass >= 2) {
+ rpnt1 = rpnt1->next_handle;
+ }
+
+ /*
+ * Make sure we still have a module, and make sure that this
+ * module was loaded with RTLD_GLOBAL.
+ */
+ if( pass != 0 )
+ {
+ if( rpnt1 == NULL ) break;
+ if( (rpnt1->flags & RTLD_GLOBAL) == 0) continue;
+ }
+
+ for(rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables);
+ rpnt; rpnt = rpnt->next) {
+ tpnt = rpnt->dyn;
+
+ /*
+ * The idea here is that if we are using dlsym, we want to
+ * first search the entire chain loaded from dlopen, and
+ * return a result from that if we found anything. If this
+ * fails, then we continue the search into the stuff loaded
+ * when the image was activated. For normal lookups, we start
+ * with rpnt == NULL, so we should never hit this.
+ */
+ if( tpnt->libtype == elf_executable
+ && weak_result != 0 )
+ {
+ break;
+ }
+
+ /*
+ * Avoid calling .urem here.
+ */
+ do_rem(hn, elf_hash_number, tpnt->nbucket);
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] +
+ tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+ /*
+ * This crap is required because the first instance of a
+ * symbol on the chain will be used for all symbol references.
+ * Thus this instance must be resolved to an address that
+ * contains the actual function,
+ */
+
+ first_def = NULL;
+
+ for(si = tpnt->elf_buckets[hn]; si; si = tpnt->chains[si]){
+ pnt = strtab + symtab[si].st_name;
+
+ if(_dl_strcmp(pnt, name) == 0 &&
+ (ELF32_ST_TYPE(symtab[si].st_info) == STT_FUNC ||
+ ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE ||
+ ELF32_ST_TYPE(symtab[si].st_info) == STT_OBJECT) &&
+ symtab[si].st_value != 0) {
+
+ /* Here we make sure that we find a module where the symbol is
+ * actually defined.
+ */
+
+ if(f_tpnt) {
+ if(!first_def) first_def = tpnt;
+ if(first_def == f_tpnt && symtab[si].st_shndx == 0)
+ continue;
+ }
+
+ switch(ELF32_ST_BIND(symtab[si].st_info)){
+ case STB_GLOBAL:
+ if ( tpnt->libtype != elf_executable
+ && ELF32_ST_TYPE(symtab[si].st_info) == STT_NOTYPE) { /* nakao */
+ data_result = tpnt->loadaddr + symtab[si].st_value; /* nakao */
+ break; /* nakao */
+ } else /* nakao */
+ return tpnt->loadaddr + symtab[si].st_value;
+ case STB_WEAK:
+ if (!weak_result) weak_result = tpnt->loadaddr + symtab[si].st_value;
+ break;
+ default: /* Do local symbols need to be examined? */
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (data_result) return data_result; /* nakao */
+ return weak_result;
+}
diff --git a/ldso/ldso/hash.h b/ldso/ldso/hash.h
new file mode 100644
index 000000000..2eeda2d46
--- /dev/null
+++ b/ldso/ldso/hash.h
@@ -0,0 +1,113 @@
+#include "link.h"
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT ((void*)-1)
+#endif
+
+struct dyn_elf{
+ unsigned int flags;
+ struct elf_resolve * dyn;
+ struct dyn_elf * next_handle; /* Used by dlopen et al. */
+ struct dyn_elf * next;
+};
+
+struct elf_resolve{
+ /* These entries must be in this order to be compatible with the interface used
+ by gdb to obtain the list of symbols. */
+ char * loadaddr;
+ char * libname;
+ unsigned int dynamic_addr;
+ struct elf_resolve * next;
+ struct elf_resolve * prev;
+ /* Nothing after this address is used by gdb. */
+ enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+ struct dyn_elf * symbol_scope;
+ unsigned short usage_count;
+ unsigned short int init_flag;
+ unsigned int nbucket;
+ unsigned int * elf_buckets;
+ /*
+ * These are only used with ELF style shared libraries
+ */
+ unsigned int nchain;
+ unsigned int * chains;
+ unsigned int dynamic_info[24];
+
+ unsigned int dynamic_size;
+ unsigned int n_phent;
+ struct elf_phdr * ppnt;
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+ int r_version;
+ struct elf_resolve * link_map;
+ unsigned long brk_fun;
+ enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+ unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+ char * loadaddr,
+ unsigned int * dynamic_info,
+ unsigned int dynamic_addr,
+ unsigned int dynamic_size);
+extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
+ unsigned int instr_addr,
+ struct elf_resolve * f_tpnt,
+ int copyrel);
+
+extern int _dl_linux_dynamic_link(void);
+
+#ifdef __mc68000__
+/* On m68k constant strings are referenced through the GOT. */
+/* XXX Requires load_addr to be defined. */
+#define SEND_STDERR(X) \
+ { const char *__s = (X); \
+ if (__s < (const char *) load_addr) __s += load_addr; \
+ _dl_write (2, __s, _dl_strlen (__s)); \
+ }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
+#endif
+extern int _dl_fdprintf(int, const char *, ...);
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern char * _dl_strdup(const char *);
+extern inline int _dl_symbol(char * name);
+unsigned long _dl_elf_hash(const char * name);
+
+extern inline int _dl_symbol(char * name)
+{
+ if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+ return 0;
+ return 1;
+}
+
+#define DL_ERROR_NOFILE 1
+#define DL_ERROR_NOZERO 2
+#define DL_ERROR_NOTELF 3
+#define DL_ERROR_NOTMAGIC 4
+#define DL_ERROR_NOTDYN 5
+#define DL_ERROR_MMAP_FAILED 6
+#define DL_ERROR_NODYNAMIC 7
+#define DL_WRONG_RELOCS 8
+#define DL_BAD_HANDLE 9
+#define DL_NO_SYMBOL 10
+
diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h
new file mode 100644
index 000000000..9bbeef1fa
--- /dev/null
+++ b/ldso/ldso/i386/dl-sysdep.h
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[2] = (int) _dl_linux_resolve; \
+ GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader. RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)){ \
+ case R_386_32: \
+ *REL += SYMBOL; \
+ break; \
+ case R_386_PC32: \
+ *REL += SYMBOL - (unsigned int) REL; \
+ break; \
+ case R_386_GLOB_DAT: \
+ case R_386_JMP_SLOT: \
+ *REL = SYMBOL; \
+ break; \
+ case R_386_RELATIVE: \
+ *REL += (unsigned int) LOAD; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START() \
+ __asm__ volatile ("leave\n\t" \
+ "jmp *%%eax\n\t" \
+ : "=a" (status) : \
+ "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base) result = (n % base)
diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c
new file mode 100644
index 000000000..3347882d6
--- /dev/null
+++ b/ldso/ldso/i386/elfinterp.c
@@ -0,0 +1,321 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char * _dl_reltypes[] = {"R_386_NONE","R_386_32","R_386_PC32","R_386_GOT32",
+ "R_386_PLT32","R_386_COPY","R_386_GLOB_DAT",
+ "R_386_JMP_SLOT","R_386_RELATIVE","R_386_GOTOFF",
+ "R_386_GOTPC","R_386_NUM"};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+References to symbols in sharable libraries can be resolved by either
+an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
+ I ever taken any courses on internals. This program was developed using
+ information available through the book "UNIX SYSTEM V RELEASE 4,
+ Programmers guide: Ansi C and Programming Support Tools", which did
+ a more than adequate job of explaining everything required to get this
+ working. */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "../string.h"
+#include "../syscall.h"
+
+#define SVR4_COMPATIBILITY
+
+extern char *_dl_progname;
+
+extern int _dl_linux_resolve(void);
+
+unsigned int _dl_linux_resolver(int dummy, int i)
+{
+ unsigned int * sp;
+ int reloc_entry;
+ int reloc_type;
+ struct elf32_rel * this_reloc;
+ char * strtab;
+ struct elf32_sym * symtab;
+ struct elf32_rel * rel_addr;
+ struct elf_resolve * tpnt;
+ int symtab_index;
+ char * new_addr;
+ char ** got_addr;
+ unsigned int instr_addr;
+ sp = &i;
+ reloc_entry = sp[1];
+ tpnt = (struct elf_resolve *) sp[0];
+
+ rel_addr = (struct elf32_rel *) (tpnt->dynamic_info[DT_JMPREL] +
+ tpnt->loadaddr);
+
+ this_reloc = rel_addr + (reloc_entry >> 3);
+ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+ symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+
+ if (reloc_type != R_386_JMP_SLOT) {
+ _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n",
+ _dl_progname);
+ _dl_exit(1);
+ };
+
+ /* Address of jump instruction to fix up */
+ instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr);
+ got_addr = (char **) instr_addr;
+
+#ifdef DEBUG
+ _dl_fdprintf(2, "Resolving symbol %s\n",
+ strtab + symtab[symtab_index].st_name);
+#endif
+
+ /* Get the address of the GOT entry */
+ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+ if(!new_addr) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_exit(1);
+ };
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+ if((unsigned int) got_addr < 0x40000000) {
+ _dl_fdprintf(2, "Calling library function: %s\n",
+ strtab + symtab[symtab_index].st_name);
+ } else {
+ *got_addr = new_addr;
+ }
+#else
+ *got_addr = new_addr;
+#endif
+ return (unsigned int) new_addr;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type){
+ int i;
+ char * strtab;
+ int reloc_type;
+ int symtab_index;
+ struct elf32_sym * symtab;
+ struct elf32_rel * rpnt;
+ unsigned int * reloc_addr;
+
+ /* Now parse the relocation information */
+ rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof(struct elf32_rel);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i++, rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+ /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+ Make sure we do not do them again */
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+ if(symtab_index && tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ switch(reloc_type){
+ case R_386_NONE: break;
+ case R_386_JMP_SLOT:
+ *reloc_addr += (unsigned int) tpnt->loadaddr;
+ break;
+ default:
+ _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if(symtab_index) _dl_fdprintf(2, "'%s'\n",
+ strtab + symtab[symtab_index].st_name);
+ _dl_exit(1);
+ };
+ };
+}
+
+int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type){
+ int i;
+ char * strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym * symtab;
+ struct elf32_rel * rpnt;
+ unsigned int * reloc_addr;
+ unsigned int symbol_addr;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof(struct elf32_rel);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i++, rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+
+ if(symtab_index) {
+
+ if(tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ symbol_addr = (unsigned int)
+ _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) reloc_addr,
+ (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), 0);
+
+ /*
+ * We want to allow undefined references to weak symbols - this might
+ * have been intentional. We should not be linking local symbols
+ * here, so all bases should be covered.
+ */
+ if(!symbol_addr &&
+ ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ }
+ }
+ switch(reloc_type){
+ case R_386_NONE:
+ break;
+ case R_386_32:
+ *reloc_addr += symbol_addr;
+ break;
+ case R_386_PC32:
+ *reloc_addr += symbol_addr - (unsigned int) reloc_addr;
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ *reloc_addr = symbol_addr;
+ break;
+ case R_386_RELATIVE:
+ *reloc_addr += (unsigned int) tpnt->loadaddr;
+ break;
+ case R_386_COPY:
+#if 0 /* Do this later */
+ _dl_fdprintf(2, "Doing copy for symbol ");
+ if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
+ _dl_fdprintf(2, "\n");
+ _dl_memcpy((void *) symtab[symtab_index].st_value,
+ (void *) symbol_addr,
+ symtab[symtab_index].st_size);
+#endif
+ break;
+ default:
+ _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if (symtab_index)
+ _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
+ _dl_exit(1);
+ };
+
+ };
+ return goof;
+}
+
+
+/* This is done as a separate step, because there are cases where
+ information is first copied and later initialized. This results in
+ the wrong information being copied. Someone at Sun was complaining about
+ a bug in the handling of _COPY by SVr4, and this may in fact be what he
+ was talking about. Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+ at all */
+
+int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
+ int rel_size, int type)
+{
+ int i;
+ char * strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym * symtab;
+ struct elf32_rel * rpnt;
+ unsigned int * reloc_addr;
+ unsigned int symbol_addr;
+ struct elf_resolve *tpnt;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ tpnt = xpnt->dyn;
+
+ rpnt = (struct elf32_rel *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof(struct elf32_rel);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i++, rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ if(reloc_type != R_386_COPY) continue;
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+ if(symtab_index) {
+
+ if(tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ symbol_addr = (unsigned int)
+ _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ xpnt->next, (int) reloc_addr, NULL, 1);
+ if(!symbol_addr) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ };
+ };
+ if (!goof)
+ _dl_memcpy((char *) symtab[symtab_index].st_value,
+ (char *) symbol_addr,
+ symtab[symtab_index].st_size);
+ };
+ return goof;
+}
+
+
diff --git a/ldso/ldso/i386/ld_sysdep.h b/ldso/ldso/i386/ld_sysdep.h
new file mode 100644
index 000000000..9bbeef1fa
--- /dev/null
+++ b/ldso/ldso/i386/ld_sysdep.h
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[2] = (int) _dl_linux_resolve; \
+ GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader. RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)){ \
+ case R_386_32: \
+ *REL += SYMBOL; \
+ break; \
+ case R_386_PC32: \
+ *REL += SYMBOL - (unsigned int) REL; \
+ break; \
+ case R_386_GLOB_DAT: \
+ case R_386_JMP_SLOT: \
+ *REL = SYMBOL; \
+ break; \
+ case R_386_RELATIVE: \
+ *REL += (unsigned int) LOAD; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START() \
+ __asm__ volatile ("leave\n\t" \
+ "jmp *%%eax\n\t" \
+ : "=a" (status) : \
+ "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base) result = (n % base)
diff --git a/ldso/ldso/i386/resolve.S b/ldso/ldso/i386/resolve.S
new file mode 100644
index 000000000..db22e7b82
--- /dev/null
+++ b/ldso/ldso/i386/resolve.S
@@ -0,0 +1,55 @@
+#if 0
+#include <sysdep.h>
+#endif
+/*
+ * These are various helper routines that are needed to run an ELF image.
+ */
+#ifndef ALIGN
+#define ALIGN 4
+#endif
+
+#ifndef NO_UNDERSCORE
+#define RUN _linux_run
+#define RESOLVE __dl_linux_resolve
+#define EXIT __interpreter_exit
+#define RESOLVER __dl_linux_resolver
+#define INIT ___loader_bootstrap
+#else
+#define RUN linux_run
+#define RESOLVE _dl_linux_resolve
+#define RESOLVER _dl_linux_resolver
+#define EXIT _interpreter_exit
+#define INIT __loader_bootstrap
+#endif
+
+.text
+.align ALIGN
+ .align 16
+
+.globl RESOLVE
+ .type RESOLVE,@function
+RESOLVE:
+ pusha /* preserve all regs */
+ lea 0x20(%esp),%eax /* eax = tpnt and reloc_entry params */
+ pushl 4(%eax) /* push copy of reloc_entry param */
+ pushl (%eax) /* push copy of tpnt param */
+ pushl %eax /* _dl_linux_resolver expects a dummy
+ * param - this could be removed */
+#ifdef __PIC__
+ call .L24
+.L24:
+ popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-.L24],%ebx
+ movl RESOLVER@GOT(%ebx),%ebx /* eax = resolved func */
+ call *%ebx
+#else
+ call RESOLVER
+#endif
+ movl %eax,0x2C(%esp) /* store func addr over original
+ * tpnt param */
+ addl $0xC,%esp /* remove copy parameters */
+ popa /* restore regs */
+ ret $4 /* jump to func removing original
+ * reloc_entry param from stack */
+.LFE2:
+ .size RESOLVE,.LFE2-RESOLVE
diff --git a/ldso/ldso/i386/sysdep.h b/ldso/ldso/i386/sysdep.h
new file mode 100644
index 000000000..9bbeef1fa
--- /dev/null
+++ b/ldso/ldso/i386/sysdep.h
@@ -0,0 +1,82 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned int*) & ARGS)
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmovl %%ebx,%0\n\t" : "=a" (X))
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[2] = (int) _dl_linux_resolve; \
+ GOT_BASE[1] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader. RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)){ \
+ case R_386_32: \
+ *REL += SYMBOL; \
+ break; \
+ case R_386_PC32: \
+ *REL += SYMBOL - (unsigned int) REL; \
+ break; \
+ case R_386_GLOB_DAT: \
+ case R_386_JMP_SLOT: \
+ *REL = SYMBOL; \
+ break; \
+ case R_386_RELATIVE: \
+ *REL += (unsigned int) LOAD; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.
+ */
+
+#define START() \
+ __asm__ volatile ("leave\n\t" \
+ "jmp *%%eax\n\t" \
+ : "=a" (status) : \
+ "d" (_dl_interpreter_exit), "a" (_dl_elf_main))
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_386
+#define MAGIC2 EM_486
+/* Used for error messages */
+#define ELF_TARGET "386/486"
+
+extern unsigned int _dl_linux_resolver(int dummy, int i);
+
+#define do_rem(result, n, base) result = (n % base)
diff --git a/ldso/ldso/ld-uClibc.c b/ldso/ldso/ld-uClibc.c
new file mode 100644
index 000000000..6b0b864cb
--- /dev/null
+++ b/ldso/ldso/ld-uClibc.c
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* 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 <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+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-linux-uclibc.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);
+
+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 int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct 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.
+ */
+void _dl_debug_state()
+{
+ return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+ unsigned int argc;
+ char ** argv, ** envp;
+ int status;
+
+ unsigned int load_addr;
+ unsigned int * got;
+ unsigned int * aux_dat;
+ int goof = 0;
+ struct elfhdr * header;
+ struct elf_resolve * tpnt;
+ struct dyn_elf * rpnt;
+ struct elf_resolve * app_tpnt;
+ unsigned int brk_addr;
+ unsigned int dl_data[AT_EGID+1];
+ unsigned char * malloc_buffer, *mmap_zero;
+ int (*_dl_atexit)(void *);
+ int * lpnt;
+ struct dynamic * dpnt;
+ unsigned int *hash_addr;
+ struct r_debug * debug_addr;
+ unsigned int *chains;
+ int indx;
+ int _dl_secure;
+
+ /* First obtain the information on the stack that tells us more about
+ what binary is loaded, where it is loaded, etc, etc */
+
+ GET_ARGV(aux_dat, args);
+ argc = *(aux_dat - 1);
+ argv = (char **) aux_dat;
+ aux_dat += argc; /* Skip over the argv pointers */
+ aux_dat++; /* Skip over NULL at end of argv */
+ envp = (char **) aux_dat;
+ while(*aux_dat) aux_dat++; /* Skip over the envp pointers */
+ aux_dat++; /* Skip over NULL at end of envp */
+ dl_data[AT_UID] = -1; /* check later to see if it is changed */
+ while(*aux_dat)
+ {
+ unsigned int * ad1;
+ ad1 = aux_dat + 1;
+ if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+ aux_dat += 2;
+ }
+
+ /* Next, locate the GOT */
+
+ load_addr = dl_data[AT_BASE];
+
+ GET_GOT(got);
+ dpnt = (struct dynamic *) (*got + 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. */
+
+ {
+ /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+ int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+ /* See if we need to relocate this address */
+ mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+ if(_dl_mmap_check_error(mmap_zero)) {
+ SEND_STDERR("dl_boot: mmap of /dev/zero 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)
+ {
+ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+ dpnt++;
+ }
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+ if(ppnt->p_type == PT_DYNAMIC) {
+ dpnt = (struct dynamic *) ppnt->p_vaddr;
+ while(dpnt->d_tag)
+ {
+ if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+ app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) 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;
+
+ /* Ugly, ugly. We need to call mprotect to change the protection of
+ the text pages so that we can do the dynamic linking. We can set the
+ protection back again once we are done */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ /* First cover the shared library/dynamic linker. */
+ if(tpnt->dynamic_info[DT_TEXTREL]) {
+ header = (struct elfhdr *) dl_data[AT_BASE];
+ ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+ for(i=0; i<header->e_phnum ; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+
+ /* Now cover the application program. */
+ if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+ }
+
+ /* 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;
+
+
+#ifdef ELF_USES_RELOCA
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+ if(!rel_addr) continue;
+
+ /* Now parse the relocation information */
+ rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+ for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+ reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ if(symtab_index) {
+ char * strtab;
+ struct elf32_sym * symtab;
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+ /* We only do a partial dynamic linking right now. The user
+ is not supposed to redefine any symbols that start with
+ a '_', so we can do this with confidence. */
+
+ if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+ symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+ if(!symbol_addr) {
+ /*
+ * This will segfault - you cannot call a function until
+ * we have finished the relocations.
+ */
+ SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+ SEND_STDERR(strtab + symtab[symtab_index].st_name);
+ SEND_STDERR(" undefined.\n");
+ goof++;
+ }
+ }
+ /*
+ * Use this machine-specific macro to perform the actual relocation.
+ */
+ PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+ }
+ }
+
+ if (goof) _dl_exit(14);
+
+ /* 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);
+ INIT_GOT(lpnt, tpnt);
+
+ /* 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;
+
+ { struct elfhdr * epnt;
+ struct elf_phdr * ppnt;
+ int i;
+
+ epnt = (struct elfhdr *) dl_data[AT_BASE];
+ tpnt->n_phent = epnt->e_phnum;
+ tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + 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;
+
+ 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 */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD) {
+ if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr)
+ brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+ }
+ if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+ /* make sure it's really there. */
+ if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+ /* OK, we have what we need - slip this one into the list. */
+ app_tpnt = _dl_add_elf_hash_table("", 0,
+ app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+ _dl_loaded_modules->libtype = elf_executable;
+ _dl_loaded_modules->ppnt = (struct elf_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]);
+#ifdef ALLOW_ZERO_PLTGOT
+ if (lpnt)
+#endif
+ INIT_GOT(lpnt, _dl_loaded_modules);
+ }
+ if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+ this before */
+ tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+ }
+ }
+ }
+
+ 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);
+
+ if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+ (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+ dl_data[AT_GID] == dl_data[AT_EGID]))
+ {
+ _dl_secure = 0;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+ }
+ else
+ {
+ _dl_secure = 1;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+ _dl_unsetenv("LD_LIBRARY_PATH", envp);
+ _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+ _dl_library_path = NULL;
+ }
+ }
+
+ _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;
+
+ if (_dl_preload) {
+ char c, *str, *str2;
+
+ str = _dl_preload;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ while (*str) {
+ str2 = str;
+ while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+ str2++;
+ c = *str2;
+ *str2 = '\0';
+ if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+ tpnt1 = _dl_load_shared_library(_dl_secure, NULL, 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) {
+ /* this is a real hack to make ldd not print the
+ library itself when run on a library. */
+ if (_dl_strcmp(_dl_progname, str) != 0)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ }
+ 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;
+ }
+ }
+ *str2 = c;
+ str = str2;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ }
+ }
+
+ {
+ int fd;
+ struct kernel_stat st;
+ char *preload;
+
+ if (!_dl_stat(LDSO_PRELOAD, &st)) {
+ if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+ _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ _dl_close (fd);
+ if (preload == (caddr_t)-1) {
+ _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ char c, *cp, *cp2;
+
+ /* convert all separators and comments to spaces */
+ for (cp = preload; *cp; /*nada*/) {
+ if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+ *cp++ = ' ';
+ } else if (*cp == '#') {
+ do
+ *cp++ = ' ';
+ while (*cp != '\n' && *cp != '\0');
+ } else {
+ cp++;
+ }
+ }
+
+ /* find start of first library */
+ for (cp = preload; *cp && *cp == ' '; cp++)
+ /*nada*/;
+
+ while (*cp) {
+ /* find end of library */
+ for (cp2 = cp; *cp && *cp != ' '; cp++)
+ /*nada*/;
+ c = *cp;
+ *cp = '\0';
+
+ tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+ if (!tpnt1) {
+ if (_dl_trace_loaded_objects)
+ _dl_fdprintf(1, "\t%s => not found\n", cp2);
+ else {
+ _dl_fdprintf(2, "%s: can't load library '%s'\n",
+ _dl_progname, cp2);
+ _dl_exit(15);
+ }
+ } else {
+ if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+
+ /* find start of next library */
+ *cp = c;
+ for (/*nada*/; *cp && *cp == ' '; cp++)
+ /*nada*/;
+ }
+
+ _dl_munmap(preload, st.st_size+1);
+ }
+ }
+ }
+ }
+
+ for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+ {
+ for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+ {
+ if(dpnt->d_tag == DT_NEEDED)
+ {
+ lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+ dpnt->d_un.d_val;
+ if (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(0, tcurr, 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 (0x%x)\n", lpnt, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+#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_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+ /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+ and we have to manually search for entries that require fixups.
+ Solaris gets this one right, from what I understand. */
+
+
+ if (_dl_symbol_tables)
+ goof += _dl_copy_fixups(_dl_symbol_tables);
+
+ 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;
+
+ {
+ int i;
+ struct elf_phdr * ppnt;
+
+ /* We had to set the protections of all pages to R/W for dynamic linking.
+ Set text pages back to R/O */
+ for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+ for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+ tpnt->dynamic_info[DT_TEXTREL])
+ _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags));
+
+ }
+
+ _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+ /*
+ * 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;
+ debug_addr->r_state = RT_CONSISTENT;
+ /* This is written in this funny way to keep gcc from inlining the
+ function call. */
+ ((void (*)(void))debug_addr->r_brk)();
+
+ 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 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]) {
+#ifdef ELF_USES_RELOCA
+ _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+ _dl_exit(17);
+#else
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+ tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+ }
+ if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+ tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+ _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+ _dl_exit(18);
+#endif
+ }
+ 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)
+ _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ else
+ goof += _dl_parse_relocation_information(tpnt,
+ tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ }
+ return goof;
+}
+
+void * _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_PRIVATE | MAP_ANONYMOUS, -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 && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if (!*pnt || *pnt != '=' || *pnt1)
+ continue;
+ return pnt+1;
+ }
+ return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+ char *pnt;
+ char *pnt1;
+ char **newenvp = envp;
+ for (pnt = *envp; pnt; pnt = *++envp) {
+ pnt1 = symbol;
+ while (*pnt && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if(!*pnt || *pnt != '=' || *pnt1)
+ *newenvp++ = *envp;
+ }
+ *newenvp++ = *envp;
+ return;
+}
+
+char * _dl_strdup(const char * string){
+ char * retval;
+ int len;
+
+ len = _dl_strlen(string);
+ retval = _dl_malloc(len + 1);
+ _dl_strcpy(retval, string);
+ return retval;
+}
+
+/* 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;
+}
diff --git a/ldso/ldso/ld_hash.h b/ldso/ldso/ld_hash.h
new file mode 100644
index 000000000..2eeda2d46
--- /dev/null
+++ b/ldso/ldso/ld_hash.h
@@ -0,0 +1,113 @@
+#include "link.h"
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT ((void*)-1)
+#endif
+
+struct dyn_elf{
+ unsigned int flags;
+ struct elf_resolve * dyn;
+ struct dyn_elf * next_handle; /* Used by dlopen et al. */
+ struct dyn_elf * next;
+};
+
+struct elf_resolve{
+ /* These entries must be in this order to be compatible with the interface used
+ by gdb to obtain the list of symbols. */
+ char * loadaddr;
+ char * libname;
+ unsigned int dynamic_addr;
+ struct elf_resolve * next;
+ struct elf_resolve * prev;
+ /* Nothing after this address is used by gdb. */
+ enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+ struct dyn_elf * symbol_scope;
+ unsigned short usage_count;
+ unsigned short int init_flag;
+ unsigned int nbucket;
+ unsigned int * elf_buckets;
+ /*
+ * These are only used with ELF style shared libraries
+ */
+ unsigned int nchain;
+ unsigned int * chains;
+ unsigned int dynamic_info[24];
+
+ unsigned int dynamic_size;
+ unsigned int n_phent;
+ struct elf_phdr * ppnt;
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+ int r_version;
+ struct elf_resolve * link_map;
+ unsigned long brk_fun;
+ enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+ unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(char * libname,
+ char * loadaddr,
+ unsigned int * dynamic_info,
+ unsigned int dynamic_addr,
+ unsigned int dynamic_size);
+extern char * _dl_find_hash(char * name, struct dyn_elf * rpnt1,
+ unsigned int instr_addr,
+ struct elf_resolve * f_tpnt,
+ int copyrel);
+
+extern int _dl_linux_dynamic_link(void);
+
+#ifdef __mc68000__
+/* On m68k constant strings are referenced through the GOT. */
+/* XXX Requires load_addr to be defined. */
+#define SEND_STDERR(X) \
+ { const char *__s = (X); \
+ if (__s < (const char *) load_addr) __s += load_addr; \
+ _dl_write (2, __s, _dl_strlen (__s)); \
+ }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
+#endif
+extern int _dl_fdprintf(int, const char *, ...);
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern char * _dl_strdup(const char *);
+extern inline int _dl_symbol(char * name);
+unsigned long _dl_elf_hash(const char * name);
+
+extern inline int _dl_symbol(char * name)
+{
+ if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+ return 0;
+ return 1;
+}
+
+#define DL_ERROR_NOFILE 1
+#define DL_ERROR_NOZERO 2
+#define DL_ERROR_NOTELF 3
+#define DL_ERROR_NOTMAGIC 4
+#define DL_ERROR_NOTDYN 5
+#define DL_ERROR_MMAP_FAILED 6
+#define DL_ERROR_NODYNAMIC 7
+#define DL_WRONG_RELOCS 8
+#define DL_BAD_HANDLE 9
+#define DL_NO_SYMBOL 10
+
diff --git a/ldso/ldso/ld_string.h b/ldso/ldso/ld_string.h
new file mode 100644
index 000000000..1ea8fd7ae
--- /dev/null
+++ b/ldso/ldso/ld_string.h
@@ -0,0 +1,112 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h> /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char * _dl_strcpy(char * dst,const char *src)
+{
+ register char *ptr = dst;
+
+ while (*src)
+ *dst++ = *src++;
+ *dst = '\0';
+
+ return ptr;
+}
+
+extern inline int _dl_strcmp(const char * s1,const char * s2)
+{
+ unsigned register char c1, c2;
+
+ do {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0')
+ return c1 - c2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+
+extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
+{
+ unsigned register char c1 = '\0';
+ unsigned register char c2 = '\0';
+
+ while (len > 0) {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0' || c1 != c2)
+ return c1 - c2;
+ len--;
+ }
+
+ return c1 - c2;
+}
+
+extern inline char * _dl_strchr(const char * str,int c)
+{
+ register char ch;
+
+ do {
+ if ((ch = *str) == c)
+ return (char *) str;
+ str++;
+ }
+ while (ch);
+
+ return 0;
+}
+
+
+extern inline size_t _dl_strlen(const char * str)
+{
+ register char *ptr = (char *) str;
+
+ while (*ptr)
+ ptr++;
+ return (ptr - str);
+}
+
+extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+ register char *a = dst;
+ register const char *b = src;
+
+ while (len--)
+ *a++ = *b++;
+
+ return dst;
+}
+
+
+extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
+{
+ unsigned char *c1 = (unsigned char *)s1;
+ unsigned char *c2 = (unsigned char *)s2;
+
+ while (len--) {
+ if (*c1 != *c2)
+ return *c1 - *c2;
+ c1++;
+ c2++;
+ }
+ return 0;
+}
+
+extern inline void * _dl_memset(void * str,int c,size_t len)
+{
+ register char *a = str;
+
+ while (len--)
+ *a++ = c;
+
+ return str;
+}
+
+#endif
diff --git a/ldso/ldso/ld_syscall.h b/ldso/ldso/ld_syscall.h
new file mode 100644
index 000000000..3cf244338
--- /dev/null
+++ b/ldso/ldso/ld_syscall.h
@@ -0,0 +1,108 @@
+#include <linux/types.h>
+#include <asm/unistd.h>
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+
+#define _dl_mmap_check_error(__res) \
+ (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+
+
+/* Here are the definitions for some syscalls that are used
+ by the dynamic linker. The idea is that we want to be able
+ to call these before the errno symbol is dynamicly linked, so
+ we use our own version here. Note that we cannot assume any
+ dynamic linking at all, so we cannot return any error codes.
+ We just punt if there is an error. */
+
+/* Do not include unistd.h, so gcc doesn't whine about
+ * _exit returning. It really doesn't return... */
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long buffer[6];
+
+ buffer[0] = (unsigned long) addr;
+ buffer[1] = (unsigned long) size;
+ buffer[2] = (unsigned long) prot;
+ buffer[3] = (unsigned long) flags;
+ buffer[4] = (unsigned long) fd;
+ buffer[5] = (unsigned long) offset;
+ return (void *) _dl_mmap_real(buffer);
+}
+
+#define __NR__dl_open __NR_open
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd,
+ const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd,
+ const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like. It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define __NR__dl_stat __NR_stat
+#define stat kernel_stat
+#define new_stat kernel_stat
+#include <asm/stat.h>
+#undef new_stat
+#undef stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(gid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+extern inline int _dl_suid_ok(void)
+{
+ uid_t uid, euid, gid, egid;
+
+ uid = _dl_getuid();
+ euid = _dl_geteuid();
+ gid = _dl_getgid();
+ egid = _dl_getegid();
+
+ if(uid == euid && gid == egid)
+ return 1;
+ else
+ return 0;
+}
+
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
new file mode 100644
index 000000000..6b0b864cb
--- /dev/null
+++ b/ldso/ldso/ldso.c
@@ -0,0 +1,1005 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* 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 <stdarg.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/unistd.h>
+#include <linux/elf.h>
+#include <linux/mman.h>
+#include "link.h"
+
+#include "sysdep.h"
+#include "hash.h"
+#include "linuxelf.h"
+#include "syscall.h"
+#include "string.h"
+
+#include "../config.h"
+
+#define ALLOW_ZERO_PLTGOT
+
+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-linux-uclibc.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);
+
+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 int _dl_linux_resolve(void);
+extern int _dl_interpreter_exit(int);
+extern char * _dl_strdup(const char *);
+extern char * _dl_getenv(char * symbol, char ** envp);
+extern void _dl_unsetenv(char * symbol, char ** envp);
+extern int _dl_fixup(struct elf_resolve * tpnt);
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+typedef struct elf32_rela ELF_RELOC;
+#else
+typedef struct 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.
+ */
+void _dl_debug_state()
+{
+ return;
+}
+
+void _dl_boot(int args);
+
+void _dl_boot(int args){
+ unsigned int argc;
+ char ** argv, ** envp;
+ int status;
+
+ unsigned int load_addr;
+ unsigned int * got;
+ unsigned int * aux_dat;
+ int goof = 0;
+ struct elfhdr * header;
+ struct elf_resolve * tpnt;
+ struct dyn_elf * rpnt;
+ struct elf_resolve * app_tpnt;
+ unsigned int brk_addr;
+ unsigned int dl_data[AT_EGID+1];
+ unsigned char * malloc_buffer, *mmap_zero;
+ int (*_dl_atexit)(void *);
+ int * lpnt;
+ struct dynamic * dpnt;
+ unsigned int *hash_addr;
+ struct r_debug * debug_addr;
+ unsigned int *chains;
+ int indx;
+ int _dl_secure;
+
+ /* First obtain the information on the stack that tells us more about
+ what binary is loaded, where it is loaded, etc, etc */
+
+ GET_ARGV(aux_dat, args);
+ argc = *(aux_dat - 1);
+ argv = (char **) aux_dat;
+ aux_dat += argc; /* Skip over the argv pointers */
+ aux_dat++; /* Skip over NULL at end of argv */
+ envp = (char **) aux_dat;
+ while(*aux_dat) aux_dat++; /* Skip over the envp pointers */
+ aux_dat++; /* Skip over NULL at end of envp */
+ dl_data[AT_UID] = -1; /* check later to see if it is changed */
+ while(*aux_dat)
+ {
+ unsigned int * ad1;
+ ad1 = aux_dat + 1;
+ if( *aux_dat <= AT_EGID ) dl_data[*aux_dat] = *ad1;
+ aux_dat += 2;
+ }
+
+ /* Next, locate the GOT */
+
+ load_addr = dl_data[AT_BASE];
+
+ GET_GOT(got);
+ dpnt = (struct dynamic *) (*got + 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. */
+
+ {
+ /* This hack is to work around a suspected asm bug in gcc-2.7.0 */
+ int zfileno;
+#define ZFILENO ((-1 & (~zfileno)) | zfileno)
+/*#define ZFILENO -1*/
+
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+ /* See if we need to relocate this address */
+ mmap_zero = malloc_buffer = (unsigned char *) _dl_mmap((void*) 0, 4096,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, ZFILENO, 0);
+ if(_dl_mmap_check_error(mmap_zero)) {
+ SEND_STDERR("dl_boot: mmap of /dev/zero 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)
+ {
+ tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) tpnt->dynamic_info[DT_TEXTREL] = 1;
+ dpnt++;
+ }
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++)
+ if(ppnt->p_type == PT_DYNAMIC) {
+ dpnt = (struct dynamic *) ppnt->p_vaddr;
+ while(dpnt->d_tag)
+ {
+ if(dpnt->d_tag > DT_JMPREL) {dpnt++; continue; }
+ app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_DEBUG) dpnt->d_un.d_val = (int) debug_addr;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) 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;
+
+ /* Ugly, ugly. We need to call mprotect to change the protection of
+ the text pages so that we can do the dynamic linking. We can set the
+ protection back again once we are done */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ /* First cover the shared library/dynamic linker. */
+ if(tpnt->dynamic_info[DT_TEXTREL]) {
+ header = (struct elfhdr *) dl_data[AT_BASE];
+ ppnt = (struct elf_phdr *) (dl_data[AT_BASE] + header->e_phoff);
+ for(i=0; i<header->e_phnum ; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+
+ /* Now cover the application program. */
+ if(app_tpnt->dynamic_info[DT_TEXTREL]) {
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) (ppnt->p_vaddr & 0xfffff000),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+ }
+
+ /* 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;
+
+
+#ifdef ELF_USES_RELOCA
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_RELA]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELASZ]);
+#else
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->dynamic_info[DT_REL]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->dynamic_info[DT_RELSZ]);
+#endif
+
+
+ if(!rel_addr) continue;
+
+ /* Now parse the relocation information */
+ rpnt = (ELF_RELOC *) (rel_addr + load_addr);
+ for(i=0; i< rel_size; i+=sizeof(ELF_RELOC), rpnt++){
+ reloc_addr = (int *) (load_addr + (int)rpnt->r_offset);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ if(symtab_index) {
+ char * strtab;
+ struct elf32_sym * symtab;
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]+load_addr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]+load_addr);
+
+ /* We only do a partial dynamic linking right now. The user
+ is not supposed to redefine any symbols that start with
+ a '_', so we can do this with confidence. */
+
+ if (!_dl_symbol(strtab + symtab[symtab_index].st_name)) continue;
+
+ symbol_addr = load_addr + symtab[symtab_index].st_value;
+
+ if(!symbol_addr) {
+ /*
+ * This will segfault - you cannot call a function until
+ * we have finished the relocations.
+ */
+ SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
+ SEND_STDERR(strtab + symtab[symtab_index].st_name);
+ SEND_STDERR(" undefined.\n");
+ goof++;
+ }
+ }
+ /*
+ * Use this machine-specific macro to perform the actual relocation.
+ */
+ PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
+ }
+ }
+
+ if (goof) _dl_exit(14);
+
+ /* 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);
+ INIT_GOT(lpnt, tpnt);
+
+ /* 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;
+
+ { struct elfhdr * epnt;
+ struct elf_phdr * ppnt;
+ int i;
+
+ epnt = (struct elfhdr *) dl_data[AT_BASE];
+ tpnt->n_phent = epnt->e_phnum;
+ tpnt->ppnt = ppnt = (struct elf_phdr *) (load_addr + 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;
+
+ 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 */
+
+ {
+ struct elf_phdr * ppnt;
+ int i;
+
+ ppnt = (struct elf_phdr *) dl_data[AT_PHDR];
+ for(i=0; i<dl_data[AT_PHNUM]; i++, ppnt++) {
+ if(ppnt->p_type == PT_LOAD) {
+ if(ppnt->p_vaddr + ppnt->p_memsz > brk_addr)
+ brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
+ }
+ if(ppnt->p_type == PT_DYNAMIC) {
+#ifndef ALLOW_ZERO_PLTGOT
+ /* make sure it's really there. */
+ if (app_tpnt->dynamic_info[DT_PLTGOT] == 0) continue;
+#endif
+ /* OK, we have what we need - slip this one into the list. */
+ app_tpnt = _dl_add_elf_hash_table("", 0,
+ app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
+ _dl_loaded_modules->libtype = elf_executable;
+ _dl_loaded_modules->ppnt = (struct elf_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]);
+#ifdef ALLOW_ZERO_PLTGOT
+ if (lpnt)
+#endif
+ INIT_GOT(lpnt, _dl_loaded_modules);
+ }
+ if(ppnt->p_type == PT_INTERP) { /* OK, fill this in - we did not have
+ this before */
+ tpnt->libname = _dl_strdup((char *) ppnt->p_offset +(dl_data[AT_PHDR] & 0xfffff000));
+ }
+ }
+ }
+
+ 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);
+
+ if ( (dl_data[AT_UID] == -1 && _dl_suid_ok()) ||
+ (dl_data[AT_UID] != -1 && dl_data[AT_UID] == dl_data[AT_EUID] &&
+ dl_data[AT_GID] == dl_data[AT_EGID]))
+ {
+ _dl_secure = 0;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_library_path = _dl_getenv("LD_LIBRARY_PATH",envp);
+ }
+ else
+ {
+ _dl_secure = 1;
+ _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+ _dl_unsetenv("LD_AOUT_PRELOAD", envp);
+ _dl_unsetenv("LD_LIBRARY_PATH", envp);
+ _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
+ _dl_library_path = NULL;
+ }
+ }
+
+ _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;
+
+ if (_dl_preload) {
+ char c, *str, *str2;
+
+ str = _dl_preload;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ while (*str) {
+ str2 = str;
+ while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
+ str2++;
+ c = *str2;
+ *str2 = '\0';
+ if (!_dl_secure || _dl_strchr(str, '/') == NULL) {
+ tpnt1 = _dl_load_shared_library(_dl_secure, NULL, 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) {
+ /* this is a real hack to make ldd not print the
+ library itself when run on a library. */
+ if (_dl_strcmp(_dl_progname, str) != 0)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", str, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ }
+ 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;
+ }
+ }
+ *str2 = c;
+ str = str2;
+ while (*str == ':' || *str == ' ' || *str == '\t')
+ str++;
+ }
+ }
+
+ {
+ int fd;
+ struct kernel_stat st;
+ char *preload;
+
+ if (!_dl_stat(LDSO_PRELOAD, &st)) {
+ if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
+ _dl_fdprintf(2, "%s: can't open file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ preload = (caddr_t)_dl_mmap(0, st.st_size+1, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ _dl_close (fd);
+ if (preload == (caddr_t)-1) {
+ _dl_fdprintf(2, "%s: can't map file '%s'\n", _dl_progname,
+ LDSO_PRELOAD);
+ } else {
+ char c, *cp, *cp2;
+
+ /* convert all separators and comments to spaces */
+ for (cp = preload; *cp; /*nada*/) {
+ if (*cp == ':' || *cp == '\t' || *cp == '\n') {
+ *cp++ = ' ';
+ } else if (*cp == '#') {
+ do
+ *cp++ = ' ';
+ while (*cp != '\n' && *cp != '\0');
+ } else {
+ cp++;
+ }
+ }
+
+ /* find start of first library */
+ for (cp = preload; *cp && *cp == ' '; cp++)
+ /*nada*/;
+
+ while (*cp) {
+ /* find end of library */
+ for (cp2 = cp; *cp && *cp != ' '; cp++)
+ /*nada*/;
+ c = *cp;
+ *cp = '\0';
+
+ tpnt1 = _dl_load_shared_library(0, NULL, cp2);
+ if (!tpnt1) {
+ if (_dl_trace_loaded_objects)
+ _dl_fdprintf(1, "\t%s => not found\n", cp2);
+ else {
+ _dl_fdprintf(2, "%s: can't load library '%s'\n",
+ _dl_progname, cp2);
+ _dl_exit(15);
+ }
+ } else {
+ if (_dl_trace_loaded_objects && !tpnt1->usage_count)
+ _dl_fdprintf(1, "\t%s => %s (0x%x)\n", cp2, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+
+ /* find start of next library */
+ *cp = c;
+ for (/*nada*/; *cp && *cp == ' '; cp++)
+ /*nada*/;
+ }
+
+ _dl_munmap(preload, st.st_size+1);
+ }
+ }
+ }
+ }
+
+ for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+ {
+ for (dpnt = (struct dynamic *)tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
+ {
+ if(dpnt->d_tag == DT_NEEDED)
+ {
+ lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+ dpnt->d_un.d_val;
+ if (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(0, tcurr, 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 (0x%x)\n", lpnt, tpnt1->libname,
+ (unsigned)tpnt1->loadaddr);
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+#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_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
+
+
+ /* Some flavors of SVr4 do not generate the R_*_COPY directive,
+ and we have to manually search for entries that require fixups.
+ Solaris gets this one right, from what I understand. */
+
+
+ if (_dl_symbol_tables)
+ goof += _dl_copy_fixups(_dl_symbol_tables);
+
+ 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;
+
+ {
+ int i;
+ struct elf_phdr * ppnt;
+
+ /* We had to set the protections of all pages to R/W for dynamic linking.
+ Set text pages back to R/O */
+ for(tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
+ for(ppnt = tpnt->ppnt, i=0; i < tpnt->n_phent; i++, ppnt++)
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W) &&
+ tpnt->dynamic_info[DT_TEXTREL])
+ _dl_mprotect((void *) (tpnt->loadaddr + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags));
+
+ }
+
+ _dl_atexit = (int (*)(void *)) _dl_find_hash("atexit", NULL, 1, NULL, 0);
+
+ /*
+ * 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;
+ debug_addr->r_state = RT_CONSISTENT;
+ /* This is written in this funny way to keep gcc from inlining the
+ function call. */
+ ((void (*)(void))debug_addr->r_brk)();
+
+ 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 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]) {
+#ifdef ELF_USES_RELOCA
+ _dl_fdprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
+ _dl_exit(17);
+#else
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
+ tpnt->dynamic_info[DT_RELSZ], 0);
+#endif
+ }
+ if(tpnt->dynamic_info[DT_RELA]) {
+#ifdef ELF_USES_RELOCA
+ if (tpnt->init_flag & RELOCS_DONE) return goof;
+ tpnt->init_flag |= RELOCS_DONE;
+
+ goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
+ tpnt->dynamic_info[DT_RELASZ], 0);
+#else
+ _dl_fdprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
+ _dl_exit(18);
+#endif
+ }
+ 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)
+ _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ else
+ goof += _dl_parse_relocation_information(tpnt,
+ tpnt->dynamic_info[DT_JMPREL],
+ tpnt->dynamic_info[DT_PLTRELSZ], 0);
+ }
+ return goof;
+}
+
+void * _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_PRIVATE | MAP_ANONYMOUS, -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 && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if (!*pnt || *pnt != '=' || *pnt1)
+ continue;
+ return pnt+1;
+ }
+ return 0;
+}
+
+void _dl_unsetenv(char *symbol, char **envp)
+{
+ char *pnt;
+ char *pnt1;
+ char **newenvp = envp;
+ for (pnt = *envp; pnt; pnt = *++envp) {
+ pnt1 = symbol;
+ while (*pnt && *pnt == *pnt1)
+ pnt1++, pnt++;
+ if(!*pnt || *pnt != '=' || *pnt1)
+ *newenvp++ = *envp;
+ }
+ *newenvp++ = *envp;
+ return;
+}
+
+char * _dl_strdup(const char * string){
+ char * retval;
+ int len;
+
+ len = _dl_strlen(string);
+ retval = _dl_malloc(len + 1);
+ _dl_strcpy(retval, string);
+ return retval;
+}
+
+/* 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;
+}
diff --git a/ldso/ldso/link.h b/ldso/ldso/link.h
new file mode 100644
index 000000000..adaa20e4a
--- /dev/null
+++ b/ldso/ldso/link.h
@@ -0,0 +1,37 @@
+#ifndef _LINK_H
+#define _LINK_H
+
+#include "elf.h"
+
+/* Header file that describes the internal data structures used by the
+ * ELF dynamic linker. */
+
+struct link_map
+{
+ /* These entries must be in this order to be compatible with the
+ * interface used by gdb to obtain the list of symbols. */
+ unsigned long l_addr; /* address at which object is mapped */
+ char *l_name; /* full name of loaded object */
+ Elf32_Dyn *l_ld; /* dynamic structure of object */
+ struct link_map *l_next;
+ struct link_map *l_prev;
+};
+
+/* The DT_DEBUG entry in the .dynamic section is given the address of
+ * this structure. gdb can pick this up to obtain the correct list of
+ * loaded modules. */
+struct r_debug
+{
+ int r_version; /* debugging info version no */
+ struct link_map *r_map; /* address of link_map */
+ unsigned long r_brk; /* address of update routine */
+ enum
+ {
+ RT_CONSISTENT,
+ RT_ADD,
+ RT_DELETE
+ } r_state;
+ unsigned long r_ldbase; /* base addr of ld.so */
+};
+
+#endif /* _LINK_H */
diff --git a/ldso/ldso/linuxelf.h b/ldso/ldso/linuxelf.h
new file mode 100644
index 000000000..cc016f6b7
--- /dev/null
+++ b/ldso/ldso/linuxelf.h
@@ -0,0 +1,137 @@
+/* This should eventually appear in the distribution version of linux/elf.h */
+#ifndef R_SPARC_NONE
+#define R_SPARC_NONE 0
+#define R_SPARC_8 1
+#define R_SPARC_16 2
+#define R_SPARC_32 3
+#define R_SPARC_DISP8 4
+#define R_SPARC_DISP16 5
+#define R_SPARC_DISP32 6
+#define R_SPARC_WDISP30 7
+#define R_SPARC_WDISP22 8
+#define R_SPARC_HI22 9
+#define R_SPARC_22 10
+#define R_SPARC_13 11
+#define R_SPARC_LO10 12
+#define R_SPARC_GOT10 13
+#define R_SPARC_GOT13 14
+#define R_SPARC_GOT22 15
+#define R_SPARC_PC10 16
+#define R_SPARC_PC22 17
+#define R_SPARC_WPLT30 18
+#define R_SPARC_COPY 19
+#define R_SPARC_GLOB_DAT 20
+#define R_SPARC_JMP_SLOT 21
+#define R_SPARC_RELATIVE 22
+#define R_SPARC_UA32 23
+#endif
+
+#ifndef R_68K_NONE
+#define R_68K_NONE 0
+#define R_68K_32 1
+#define R_68K_16 2
+#define R_68K_8 3
+#define R_68K_PC32 4
+#define R_68K_PC16 5
+#define R_68K_PC8 6
+#define R_68K_GOT32 7
+#define R_68K_GOT16 8
+#define R_68K_GOT8 9
+#define R_68K_GOT32O 10
+#define R_68K_GOT16O 11
+#define R_68K_GOT8O 12
+#define R_68K_PLT32 13
+#define R_68K_PLT16 14
+#define R_68K_PLT8 15
+#define R_68K_PLT32O 16
+#define R_68K_PLT16O 17
+#define R_68K_PLT8O 18
+#define R_68K_COPY 19
+#define R_68K_GLOB_DAT 20
+#define R_68K_JMP_SLOT 21
+#define R_68K_RELATIVE 22
+#define R_68K_NUM 23
+#endif
+
+/*
+ * These constants define the elements of the auxiliary vector used to
+ * pass additional information from the kernel to an ELF application.
+ */
+
+#ifndef AT_NULL
+typedef struct
+{
+ int a_type;
+ union{
+ long a_val;
+ void *p_ptr;
+ void (*a_fcn)();
+ } a_un;
+} auxv_t;
+
+/*
+ * Values of a_type... These often appear in the file /usr/include/sys/auxv.h
+ * on SVr4 systems.
+ */
+#define AT_NULL 0
+#define AT_IGNORE 1
+#define AT_EXECFD 2
+#define AT_PHDR 3
+#define AT_PHENT 4
+#define AT_PHNUM 5
+#define AT_PAGESZ 6
+#define AT_BASE 7
+#define AT_FLAGS 8
+#define AT_ENTRY 9
+#endif
+#ifndef AT_NOTELF
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#endif
+
+extern int _dl_linux_resolve(void);
+extern struct elf_resolve * _dl_load_shared_library(int secure,
+ struct elf_resolve *, char * libname);
+extern void * _dl_malloc(int size);
+extern int _dl_map_cache(void);
+extern int _dl_unmap_cache(void);
+
+extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
+ char * libname, int);
+int _dl_copy_fixups(struct dyn_elf * tpnt);
+
+extern int linux_run(int argc, char * argv[]);
+
+extern void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type);
+
+extern int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type);
+extern int _dl_parse_copy_information(struct dyn_elf * rpnt, int rel_addr,
+ int rel_size, int type);
+
+
+/* This means that we may be forced to manually search for copy fixups
+ which were omitted by the linker. We cannot depend upon the DT_TEXTREL
+ to tell us whether there are fixups in a text section or not. */
+
+#ifndef SVR4_BUGCOMPAT
+#define SVR4_BUGCOMPAT 1
+#endif
+
+#ifndef PF_R
+#define PF_R 4
+#define PF_W 2
+#define PF_X 1
+#endif
+
+/* Convert between the Linux flags for page protections and the
+ ones specified in the ELF standard. */
+
+#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
+ (((X) & PF_W) ? PROT_WRITE : 0) | \
+ (((X) & PF_X) ? PROT_EXEC : 0))
+
diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h
new file mode 100644
index 000000000..24af47ca0
--- /dev/null
+++ b/ldso/ldso/m68k/dl-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); \
+ break; \
+ case R_68K_RELATIVE: /* Compatibility kludge */ \
+ *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+ break; \
+ default: \
+ _dl_exit (1); \
+ }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+ is done. */
+
+#define START() \
+ __asm__ volatile ("unlk %%a6\n\t" \
+ "jmp %0@" \
+ : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+ Not needed for m68k. */
+#define do_rem(result, n, base) ((result) = (n) % (base))
diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c
new file mode 100644
index 000000000..9b73efd3f
--- /dev/null
+++ b/ldso/ldso/m68k/elfinterp.c
@@ -0,0 +1,358 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1993, Eric Youngdale.
+ Copyright (C) 1995, Andreas Schwab.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Adapted to ELF/68k by Andreas Schwab. */
+
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char *_dl_reltypes[] =
+{
+ "R_68K_NONE",
+ "R_68K_32", "R_68K_16", "R_68K_8",
+ "R_68K_PC32", "R_68K_PC16", "R_68K_PC8",
+ "R_68K_GOT32", "R_68K_GOT16", "R_68K_GOT8",
+ "R_68K_GOT32O", "R_68K_GOT16O", "R_68K_GOT8O",
+ "R_68K_PLT32", "R_68K_PLT16", "R_68K_PLT8",
+ "R_68K_PLT32O", "R_68K_PLT16O", "R_68K_PLT8O",
+ "R_68K_COPY", "R_68K_GLOB_DAT", "R_68K_JMP_SLOT", "R_68K_RELATIVE",
+ "R_68K_NUM"
+};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+ References to symbols in sharable libraries can be resolved by either
+ an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
+ I ever taken any courses on internals. This program was developed using
+ information available through the book "UNIX SYSTEM V RELEASE 4,
+ Programmers guide: Ansi C and Programming Support Tools", which did
+ a more than adequate job of explaining everything required to get this
+ working. */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include <linux/elf.h>
+
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include "../syscall.h"
+#include "../string.h"
+
+extern char *_dl_progname;
+
+unsigned int
+_dl_linux_resolver (int dummy1, int dummy2,
+ struct elf_resolve *tpnt, int reloc_entry)
+{
+ int reloc_type;
+ struct elf32_rela *this_reloc;
+ char *strtab;
+ struct elf32_sym *symtab;
+ char *rel_addr;
+ int symtab_index;
+ char *new_addr;
+ char **got_addr;
+ unsigned int instr_addr;
+
+ rel_addr = tpnt->loadaddr + tpnt->dynamic_info[DT_JMPREL];
+ this_reloc = (struct elf32_rela *) (rel_addr + reloc_entry);
+ reloc_type = ELF32_R_TYPE (this_reloc->r_info);
+ symtab_index = ELF32_R_SYM (this_reloc->r_info);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+
+ if (reloc_type != R_68K_JMP_SLOT)
+ {
+ _dl_fdprintf (2, "%s: incorrect relocation type in jump relocations\n",
+ _dl_progname);
+ _dl_exit (1);
+ }
+
+ /* Address of jump instruction to fix up. */
+ instr_addr = (int) this_reloc->r_offset + (int) tpnt->loadaddr;
+ got_addr = (char **) instr_addr;
+
+#ifdef DEBUG
+ _dl_fdprintf (2, "Resolving symbol %s\n",
+ strtab + symtab[symtab_index].st_name);
+#endif
+
+ /* Get the address of the GOT entry. */
+ new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+ if (!new_addr)
+ {
+ _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_exit (1);
+ }
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+ if ((unsigned int) got_addr < 0x40000000)
+ _dl_fdprintf (2, "Calling library function: %s\n",
+ strtab + symtab[symtab_index].st_name);
+ else
+#endif
+ *got_addr = new_addr;
+ return (unsigned int) new_addr;
+}
+
+void
+_dl_parse_lazy_relocation_information (struct elf_resolve *tpnt, int rel_addr,
+ int rel_size, int type)
+{
+ int i;
+ char *strtab;
+ int reloc_type;
+ int symtab_index;
+ struct elf32_sym *symtab;
+ struct elf32_rela *rpnt;
+ unsigned int *reloc_addr;
+
+ /* Now parse the relocation information. */
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof (struct elf32_rela);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for (i = 0; i < rel_size; i++, rpnt++)
+ {
+ reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE (rpnt->r_info);
+ symtab_index = ELF32_R_SYM (rpnt->r_info);
+
+ /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+ Make sure we do not do them again. */
+ if (tpnt->libtype == program_interpreter
+ && (!symtab_index
+ || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+ continue;
+
+ switch (reloc_type)
+ {
+ case R_68K_NONE:
+ break;
+ case R_68K_JMP_SLOT:
+ *reloc_addr += (unsigned int) tpnt->loadaddr;
+ break;
+ default:
+ _dl_fdprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if (symtab_index)
+ _dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
+ _dl_fdprintf (2, "\n");
+ _dl_exit (1);
+ }
+ }
+}
+
+int
+_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr,
+ int rel_size, int type)
+{
+ int i;
+ char *strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym *symtab;
+ struct elf32_rela *rpnt;
+ unsigned int *reloc_addr;
+ unsigned int symbol_addr;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof (struct elf32_rela);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for (i = 0; i < rel_size; i++, rpnt++)
+ {
+ reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE (rpnt->r_info);
+ symtab_index = ELF32_R_SYM (rpnt->r_info);
+ symbol_addr = 0;
+
+ if (tpnt->libtype == program_interpreter
+ && (!symtab_index
+ || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+ continue;
+
+ if (symtab_index)
+ {
+ symbol_addr = (unsigned int)
+ _dl_find_hash (strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) reloc_addr,
+ reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, 0);
+
+ /* We want to allow undefined references to weak symbols -
+ this might have been intentional. We should not be
+ linking local symbols here, so all bases should be
+ covered. */
+ if (!symbol_addr
+ && ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_GLOBAL)
+ {
+ _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ }
+ }
+ switch (reloc_type)
+ {
+ case R_68K_NONE:
+ break;
+ case R_68K_8:
+ *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+ case R_68K_16:
+ *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+ case R_68K_32:
+ *reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+ case R_68K_PC8:
+ *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
+ - (unsigned int) reloc_addr);
+ break;
+ case R_68K_PC16:
+ *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
+ - (unsigned int) reloc_addr);
+ break;
+ case R_68K_PC32:
+ *reloc_addr = (symbol_addr + rpnt->r_addend
+ - (unsigned int) reloc_addr);
+ break;
+ case R_68K_GLOB_DAT:
+ case R_68K_JMP_SLOT:
+ *reloc_addr = symbol_addr;
+ break;
+ case R_68K_RELATIVE:
+ *reloc_addr = ((unsigned int) tpnt->loadaddr
+ /* Compatibility kludge. */
+ + (rpnt->r_addend ? : *reloc_addr));
+ break;
+ case R_68K_COPY:
+#if 0 /* Do this later. */
+ _dl_fdprintf (2, "Doing copy");
+ if (symtab_index)
+ _dl_fdprintf (2, " for symbol %s",
+ strtab + symtab[symtab_index].st_name);
+ _dl_fdprintf (2, "\n");
+ _dl_memcpy ((void *) symtab[symtab_index].st_value,
+ (void *) symbol_addr,
+ symtab[symtab_index].st_size);
+#endif
+ break;
+ default:
+ _dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf (2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if (symtab_index)
+ _dl_fdprintf (2, "'%s'", strtab + symtab[symtab_index].st_name);
+ _dl_fdprintf (2, "\n");
+ _dl_exit (1);
+ }
+
+ }
+ return goof;
+}
+
+/* This is done as a separate step, because there are cases where
+ information is first copied and later initialized. This results in
+ the wrong information being copied. Someone at Sun was complaining about
+ a bug in the handling of _COPY by SVr4, and this may in fact be what he
+ was talking about. Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+ at all. */
+
+int
+_dl_parse_copy_information (struct dyn_elf *xpnt, int rel_addr,
+ int rel_size, int type)
+{
+ int i;
+ char *strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym *symtab;
+ struct elf32_rela *rpnt;
+ unsigned int *reloc_addr;
+ unsigned int symbol_addr;
+ struct elf_resolve *tpnt;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ tpnt = xpnt->dyn;
+
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+ rel_size = rel_size / sizeof (struct elf32_rela);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB]
+ + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for (i = 0; i < rel_size; i++, rpnt++)
+ {
+ reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE (rpnt->r_info);
+ if (reloc_type != R_68K_COPY)
+ continue;
+ symtab_index = ELF32_R_SYM (rpnt->r_info);
+ symbol_addr = 0;
+ if (tpnt->libtype == program_interpreter
+ && (!symtab_index
+ || _dl_symbol (strtab + symtab[symtab_index].st_name)))
+ continue;
+ if (symtab_index)
+ {
+ symbol_addr = (unsigned int)
+ _dl_find_hash (strtab + symtab[symtab_index].st_name,
+ xpnt->next, (int) reloc_addr, NULL, 1);
+ if (!symbol_addr)
+ {
+ _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ }
+ }
+ if (!goof)
+ _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
+ symtab[symtab_index].st_size);
+ }
+ return goof;
+}
diff --git a/ldso/ldso/m68k/ld_sysdep.h b/ldso/ldso/m68k/ld_sysdep.h
new file mode 100644
index 000000000..24af47ca0
--- /dev/null
+++ b/ldso/ldso/m68k/ld_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); \
+ break; \
+ case R_68K_RELATIVE: /* Compatibility kludge */ \
+ *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+ break; \
+ default: \
+ _dl_exit (1); \
+ }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+ is done. */
+
+#define START() \
+ __asm__ volatile ("unlk %%a6\n\t" \
+ "jmp %0@" \
+ : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+ Not needed for m68k. */
+#define do_rem(result, n, base) ((result) = (n) % (base))
diff --git a/ldso/ldso/m68k/resolve.S b/ldso/ldso/m68k/resolve.S
new file mode 100644
index 000000000..9b1a24c68
--- /dev/null
+++ b/ldso/ldso/m68k/resolve.S
@@ -0,0 +1,29 @@
+#if 0
+#include <sysdep.h>
+#endif
+/*
+ * These are various helper routines that are needed to run an ELF image.
+ */
+
+#ifdef NO_UNDERSCORE
+#define __dl_linux_resolve _dl_linux_resolve
+#define __dl_linux_resolver _dl_linux_resolver
+#endif
+
+.text
+.even
+
+.globl __dl_linux_resolve
+ .type __dl_linux_resolve,@function
+__dl_linux_resolve:
+ moveml %a0/%a1,%sp@-
+#ifdef __PIC__
+ bsrl __dl_linux_resolver@PLTPC
+#else
+ jbsr __dl_linux_resolver
+#endif
+ moveml %sp@+,%a0/%a1
+ addql #8,%sp
+ jmp @(%d0)
+.LFE2:
+ .size __dl_linux_resolve,.LFE2-__dl_linux_resolve
diff --git a/ldso/ldso/m68k/sysdep.h b/ldso/ldso/m68k/sysdep.h
new file mode 100644
index 000000000..24af47ca0
--- /dev/null
+++ b/ldso/ldso/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); \
+ break; \
+ case R_68K_RELATIVE: /* Compatibility kludge */ \
+ *(REL) = ((unsigned int) (LOAD) + ((RELP)->r_addend ? : *(REL))); \
+ break; \
+ default: \
+ _dl_exit (1); \
+ }
+
+
+/* Transfer control to the user's application, once the dynamic loader
+ is done. */
+
+#define START() \
+ __asm__ volatile ("unlk %%a6\n\t" \
+ "jmp %0@" \
+ : : "a" (_dl_elf_main));
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_68K
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "m68k"
+
+struct elf_resolve;
+extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
+
+/* Define this because we do not want to call .udiv in the library.
+ Not needed for m68k. */
+#define do_rem(result, n, base) ((result) = (n) % (base))
diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c
new file mode 100644
index 000000000..9d1cd0ff5
--- /dev/null
+++ b/ldso/ldso/readelflib1.c
@@ -0,0 +1,588 @@
+/* Load an ELF sharable library into memory.
+
+ Copyright (C) 1993-1996, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+/* This file contains the helper routines to load an ELF sharable
+ library into memory and add the symbol table info to the chain. */
+
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "string.h"
+/*#include <stdlib.h>*/
+#include <linux/mman.h>
+#include <linux/stat.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+#ifdef USE_CACHE
+#include "../config.h"
+#endif
+
+extern char *_dl_progname;
+
+#ifdef USE_CACHE
+
+static caddr_t _dl_cache_addr = NULL;
+static size_t _dl_cache_size = 0;
+
+int _dl_map_cache(void)
+{
+ int fd;
+ struct kernel_stat st;
+ header_t *header;
+ libentry_t *libent;
+ int i, strtabsize;
+
+ if (_dl_cache_addr == (caddr_t)-1)
+ return -1;
+ else if (_dl_cache_addr != NULL)
+ return 0;
+
+ if (_dl_stat(LDSO_CACHE, &st) || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0)
+ {
+ _dl_fdprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
+ _dl_cache_addr = (caddr_t)-1; /* so we won't try again */
+ return -1;
+ }
+
+ _dl_cache_size = st.st_size;
+ _dl_cache_addr = (caddr_t)_dl_mmap(0, _dl_cache_size, PROT_READ,
+ MAP_SHARED, fd, 0);
+ _dl_close (fd);
+ if (_dl_cache_addr == (caddr_t)-1)
+ {
+ _dl_fdprintf(2, "%s: can't map cache '%s'\n", _dl_progname, LDSO_CACHE);
+ return -1;
+ }
+
+ header = (header_t *)_dl_cache_addr;
+
+ if (_dl_cache_size < sizeof (header_t) ||
+ _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) ||
+ _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN) ||
+ _dl_cache_size <
+ (sizeof (header_t) + header->nlibs * sizeof (libentry_t)) ||
+ _dl_cache_addr[_dl_cache_size-1] != '\0')
+ {
+ _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+ goto fail;
+ }
+
+ strtabsize = _dl_cache_size - sizeof (header_t) -
+ header->nlibs * sizeof (libentry_t);
+ libent = (libentry_t *)&header[1];
+
+ for (i = 0; i < header->nlibs; i++)
+ {
+ if (libent[i].sooffset >= strtabsize ||
+ libent[i].liboffset >= strtabsize)
+ {
+ _dl_fdprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ _dl_munmap(_dl_cache_addr, _dl_cache_size);
+ _dl_cache_addr = (caddr_t)-1;
+ return -1;
+}
+
+int _dl_unmap_cache(void)
+{
+ if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t)-1)
+ return -1;
+
+#if 1
+ _dl_munmap (_dl_cache_addr, _dl_cache_size);
+ _dl_cache_addr = NULL;
+#endif
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Used to return error codes back to dlopen et. al.
+ */
+
+unsigned int _dl_error_number;
+unsigned int _dl_internal_error_number;
+
+struct elf_resolve * _dl_load_shared_library(int secure,
+ struct elf_resolve * tpnt, char * full_libname) {
+ char * pnt, *pnt1, *pnt2;
+ struct elf_resolve *tpnt1 = NULL;
+ char mylibname[2050];
+ char * libname;
+
+ _dl_internal_error_number = 0;
+
+ /* quick hack to ensure mylibname buffer doesn't overflow. don't
+ allow full_libname or any directory to be longer than 1024. */
+ if (_dl_strlen(full_libname) > 1024)
+ goto goof;
+
+ pnt = libname = full_libname;
+ while (*pnt) {
+ if(*pnt == '/') libname = pnt+1;
+ pnt++;
+ }
+
+ /* If the filename has any '/', try it straight and leave it at that.
+ For IBCS2 compatibility under linux, we substitute the string
+ /usr/i486-sysv4/lib for /usr/lib in library names. */
+
+ if (libname != full_libname) {
+ tpnt1 = _dl_load_elf_shared_library(secure, full_libname, 0);
+ if (tpnt1)
+ return tpnt1;
+ goto goof;
+ }
+
+ /*
+ * The ABI specifies that RPATH is searched before LD_*_PATH or
+ * the default path of /usr/lib.
+ * Check in rpath directories
+ */
+ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+ if (tpnt->libtype == elf_executable) {
+ pnt1 = (char *)tpnt->dynamic_info[DT_RPATH];
+ if(pnt1) {
+ pnt1 += (unsigned int) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
+ while(*pnt1){
+ pnt2 = mylibname;
+ while(*pnt1 && *pnt1 != ':') {
+ if (pnt2 - mylibname < 1024)
+ *pnt2++ = *pnt1++;
+ else
+ pnt1++;
+ }
+ if (pnt2 - mylibname >= 1024)
+ break;
+ if(pnt2[-1] != '/') *pnt2++ = '/';
+ pnt = libname;
+ while(*pnt) *pnt2++ = *pnt++;
+ *pnt2++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if(tpnt1) return tpnt1;
+ if(*pnt1 == ':') pnt1++;
+ }
+ }
+ }
+ }
+
+
+ /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
+ pnt1 = _dl_library_path;
+ if (pnt1 && *pnt1) {
+ while (*pnt1) {
+ pnt2 = mylibname;
+ while(*pnt1 && *pnt1 != ':' && *pnt1 != ';') {
+ if (pnt2 - mylibname < 1024)
+ *pnt2++ = *pnt1++;
+ else
+ pnt1++;
+ }
+ if (pnt2 - mylibname >= 1024)
+ break;
+ if(pnt2[-1] != '/') *pnt2++ = '/';
+ pnt = libname;
+ while(*pnt) *pnt2++ = *pnt++;
+ *pnt2++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if(tpnt1) return tpnt1;
+ if(*pnt1 == ':' || *pnt1 == ';') pnt1++;
+ }
+ }
+
+
+ /*
+ * Where should the cache be searched? There is no such concept in the
+ * ABI, so we have some flexibility here. For now, search it before
+ * the default path of /usr/lib.
+ */
+#ifdef USE_CACHE
+ if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t)-1)
+ {
+ int i;
+ header_t *header = (header_t *)_dl_cache_addr;
+ libentry_t *libent = (libentry_t *)&header[1];
+ char *strs = (char *)&libent[header->nlibs];
+
+ for (i = 0; i < header->nlibs; i++)
+ {
+ if ((libent[i].flags == LIB_ELF ||
+ libent[i].flags == LIB_ELF_LIBC5) &&
+ _dl_strcmp(libname, strs+libent[i].sooffset) == 0 &&
+ (tpnt1 = _dl_load_elf_shared_library(secure, strs+libent[i].liboffset, 0)))
+ return tpnt1;
+ }
+ }
+#endif
+
+
+#ifdef UCLIBC_DEVEL
+
+ /* Check in /usr/<arch>-linux-uclibc/lib */
+ pnt1 = UCLIBC_INSTALL_DIR"/lib";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+
+#else /* UCLIBC_DEVEL */
+
+ /* Check in /usr/lib */
+ pnt1 = "/usr/lib/";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+
+ /* Check in /lib */
+ /* try "/lib/". */
+ pnt1 = "/lib/";
+ pnt = mylibname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ pnt1 = libname;
+ while(*pnt1) *pnt++ = *pnt1++;
+ *pnt++ = 0;
+ tpnt1 = _dl_load_elf_shared_library(secure, mylibname, 0);
+ if (tpnt1) return tpnt1;
+#endif /* UCLIBC_DEVEL */
+
+goof:
+ /* Well, we shot our wad on that one. All we can do now is punt */
+ if (_dl_internal_error_number) _dl_error_number = _dl_internal_error_number;
+ else _dl_error_number = DL_ERROR_NOFILE;
+ return NULL;
+}
+
+/*
+ * Read one ELF library into memory, mmap it into the correct locations and
+ * add the symbol info to the symbol chain. Perform any relocations that
+ * are required.
+ */
+
+//extern _elf_rtbndr(void);
+
+struct elf_resolve * _dl_load_elf_shared_library(int secure,
+ char * libname, int flag) {
+ struct elfhdr * epnt;
+ unsigned int dynamic_addr = 0;
+ unsigned int dynamic_size = 0;
+ struct dynamic * dpnt;
+ struct elf_resolve * tpnt;
+ struct elf_phdr * ppnt;
+ int piclib;
+ char * status;
+ int flags;
+ char header[4096];
+ int dynamic_info[24];
+ int * lpnt;
+ unsigned int libaddr;
+ unsigned int minvma=0xffffffff, maxvma=0;
+
+ int i;
+ int infile;
+
+ /* If this file is already loaded, skip this step */
+ tpnt = _dl_check_hashed_files(libname);
+ if(tpnt) return tpnt;
+
+ /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
+ we don't load the library if it isn't setuid. */
+
+ if (secure) {
+ struct kernel_stat st;
+ if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
+ return NULL;
+ }
+
+ libaddr = 0;
+ infile = _dl_open(libname, O_RDONLY);
+ if(infile < 0)
+ {
+#if 0
+ /*
+ * NO! When we open shared libraries we may search several paths.
+ * it is inappropriate to generate an error here.
+ */
+ _dl_fdprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
+#endif
+ _dl_internal_error_number = DL_ERROR_NOFILE;
+ return NULL;
+ }
+
+ _dl_read(infile, header, sizeof(header));
+ epnt = (struct elfhdr *) header;
+ if (epnt->e_ident[0] != 0x7f ||
+ epnt->e_ident[1] != 'E' ||
+ epnt->e_ident[2] != 'L' ||
+ epnt->e_ident[3] != 'F') {
+ _dl_fdprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_NOTELF;
+ _dl_close(infile);
+ return NULL;
+ };
+
+ if((epnt->e_type != ET_DYN) ||
+ (epnt->e_machine != MAGIC1
+#ifdef MAGIC2
+ && epnt->e_machine != MAGIC2
+#endif
+ )){
+ _dl_internal_error_number = (epnt->e_type != ET_DYN ? DL_ERROR_NOTDYN : DL_ERROR_NOTMAGIC);
+ _dl_fdprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n",
+ _dl_progname, libname);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+ piclib = 1;
+ for(i=0;i < epnt->e_phnum; i++){
+
+ if(ppnt->p_type == PT_DYNAMIC) {
+ if (dynamic_addr)
+ _dl_fdprintf(2, "%s: '%s' has more than one dynamic section\n",
+ _dl_progname, libname);
+ dynamic_addr = ppnt->p_vaddr;
+ dynamic_size = ppnt->p_filesz;
+ };
+
+ if(ppnt->p_type == PT_LOAD) {
+ /* See if this is a PIC library. */
+ if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+ piclib = 0;
+ minvma=ppnt->p_vaddr;
+ }
+ if(piclib && ppnt->p_vaddr < minvma) {
+ minvma = ppnt->p_vaddr;
+ }
+ if(((unsigned int)ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
+ maxvma = ppnt->p_vaddr + ppnt->p_memsz;
+ }
+ }
+ ppnt++;
+ };
+
+ maxvma=(maxvma+0xfffU)&~0xfffU;
+ minvma=minvma&~0xffffU;
+
+ flags = MAP_PRIVATE /*| MAP_DENYWRITE*/;
+ if(!piclib) flags |= MAP_FIXED;
+
+ status = (char *) _dl_mmap((char *) (piclib?0:minvma),
+ maxvma-minvma,
+ PROT_NONE,
+ flags | MAP_ANONYMOUS, -1,
+ 0);
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '/dev/zero'\n", _dl_progname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_close(infile);
+ return NULL;
+ };
+ libaddr=(unsigned int)status;
+ flags|=MAP_FIXED;
+
+ /* Get the memory to store the library */
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+
+ for(i=0;i < epnt->e_phnum; i++){
+ if(ppnt->p_type == PT_LOAD) {
+
+ /* See if this is a PIC library. */
+ if(i == 0 && ppnt->p_vaddr > 0x1000000) {
+ piclib = 0;
+ /* flags |= MAP_FIXED; */
+ }
+
+
+
+ if(ppnt->p_flags & PF_W) {
+ unsigned int map_size;
+ char * cpnt;
+
+ status = (char *) _dl_mmap((char *) ((piclib?libaddr:0) +
+ (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags),
+ flags, infile,
+ ppnt->p_offset & 0x7ffff000);
+
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_munmap((char *)libaddr, maxvma-minvma);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ /* Pad the last page with zeroes. */
+ cpnt =(char *) (status + (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz);
+ while(((unsigned int) cpnt) & 0xfff) *cpnt++ = 0;
+
+/* I am not quite sure if this is completely correct to do or not, but
+ the basic way that we handle bss segments is that we mmap /dev/zero if
+ there are any pages left over that are not mapped as part of the file */
+
+ map_size = (ppnt->p_vaddr + ppnt->p_filesz + 0xfff) & 0xfffff000;
+ if(map_size < ppnt->p_vaddr + ppnt->p_memsz)
+ status = (char *) _dl_mmap((char *) map_size + (piclib?libaddr:0),
+ ppnt->p_vaddr + ppnt->p_memsz - map_size,
+ LXFLAGS(ppnt->p_flags),
+ flags | MAP_ANONYMOUS, -1, 0);
+ } else
+ status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & 0xfffff000) +
+ (piclib?libaddr:0),
+ (ppnt->p_vaddr & 0xfff) + ppnt->p_filesz,
+ LXFLAGS(ppnt->p_flags),
+ flags, infile,
+ ppnt->p_offset & 0x7ffff000);
+ if(_dl_mmap_check_error(status)) {
+ _dl_fdprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
+ _dl_internal_error_number = DL_ERROR_MMAP_FAILED;
+ _dl_munmap((char *)libaddr, maxvma-minvma);
+ _dl_close(infile);
+ return NULL;
+ };
+
+ /* if(libaddr == 0 && piclib) {
+ libaddr = (unsigned int) status;
+ flags |= MAP_FIXED;
+ }; */
+ };
+ ppnt++;
+ };
+ _dl_close(infile);
+
+ /* For a non-PIC library, the addresses are all absolute */
+ if(piclib) {
+ dynamic_addr += (unsigned int) libaddr;
+ }
+
+ /*
+ * OK, the ELF library is now loaded into VM in the correct locations
+ * The next step is to go through and do the dynamic linking (if needed).
+ */
+
+ /* Start by scanning the dynamic section to get all of the pointers */
+
+ if(!dynamic_addr) {
+ _dl_internal_error_number = DL_ERROR_NODYNAMIC;
+ _dl_fdprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname);
+ return NULL;
+ }
+
+ dpnt = (struct dynamic *) dynamic_addr;
+
+ dynamic_size = dynamic_size / sizeof(struct dynamic);
+ _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
+ for(i=0; i< dynamic_size; i++){
+ if( dpnt->d_tag > DT_JMPREL ) {dpnt++; continue; }
+ dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+ if(dpnt->d_tag == DT_TEXTREL ||
+ SVR4_BUGCOMPAT) dynamic_info[DT_TEXTREL] = 1;
+ dpnt++;
+ };
+
+ /* If the TEXTREL is set, this means that we need to make the pages
+ writable before we perform relocations. Do this now. They get set back
+ again later. */
+
+ if (dynamic_info[DT_TEXTREL]) {
+ ppnt = (struct elf_phdr *) &header[epnt->e_phoff];
+ for(i=0;i < epnt->e_phnum; i++, ppnt++){
+ if(ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
+ _dl_mprotect((void *) ((piclib?libaddr:0) + (ppnt->p_vaddr & 0xfffff000)),
+ (ppnt->p_vaddr & 0xfff) + (unsigned int) ppnt->p_filesz,
+ PROT_READ | PROT_WRITE | PROT_EXEC);
+ }
+ }
+
+
+ tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr,
+ dynamic_size);
+
+ tpnt->ppnt = (struct elf_phdr *) (tpnt->loadaddr + epnt->e_phoff);
+ tpnt->n_phent = epnt->e_phnum;
+
+ /*
+ * OK, the next thing we need to do is to insert the dynamic linker into
+ * the proper entry in the GOT so that the PLT symbols can be properly
+ * resolved.
+ */
+
+ lpnt = (int *) dynamic_info[DT_PLTGOT];
+
+ if(lpnt) {
+ lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
+ INIT_GOT(lpnt, tpnt);
+ };
+
+ return tpnt;
+}
+
+/* Ugly, ugly. Some versions of the SVr4 linker fail to generate COPY
+ relocations for global variables that are present both in the image and
+ the shared library. Go through and do it manually. If the images
+ are guaranteed to be generated by a trustworthy linker, then this
+ step can be skipped. */
+
+int _dl_copy_fixups(struct dyn_elf * rpnt)
+{
+ int goof = 0;
+ struct elf_resolve * tpnt;
+
+ if(rpnt->next) goof += _dl_copy_fixups(rpnt->next);
+ else return 0;
+
+ tpnt = rpnt->dyn;
+
+ if (tpnt->init_flag & COPY_RELOCS_DONE) return goof;
+ tpnt->init_flag |= COPY_RELOCS_DONE;
+
+#ifdef ELF_USES_RELOCA
+ goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_RELA],
+ tpnt->dynamic_info[DT_RELASZ], 0);
+
+#else
+ goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
+ tpnt->dynamic_info[DT_RELSZ], 0);
+
+#endif
+ return goof;
+}
+
diff --git a/ldso/ldso/sparc/DEFS.h b/ldso/ldso/sparc/DEFS.h
new file mode 100644
index 000000000..4b9abccfd
--- /dev/null
+++ b/ldso/ldso/sparc/DEFS.h
@@ -0,0 +1,5 @@
+#define FUNC(name) \
+ .global name; \
+ .type name,@function; \
+ .align 4; \
+ name:
diff --git a/ldso/ldso/sparc/dl-sysdep.h b/ldso/ldso/sparc/dl-sysdep.h
new file mode 100644
index 000000000..1d4c0354f
--- /dev/null
+++ b/ldso/ldso/sparc/dl-sysdep.h
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here. We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT. For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots. The PLT should
+ * look like:
+ *
+ * save %sp, -64, %sp
+ * call _dl_linux_resolve
+ * nop
+ * .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
+ GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+ GOT_BASE[2] = 0x01000000; /* nop */ \
+ GOT_BASE[3] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)) { \
+ case R_SPARC_32: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_GLOB_DAT: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_JMP_SLOT: \
+ REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
+ REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
+ break; \
+ case R_SPARC_NONE: \
+ break; \
+ case R_SPARC_WDISP30: \
+ break; \
+ case R_SPARC_RELATIVE: \
+ *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done. The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START() \
+ __asm__ volatile ( \
+ "add %%g0,%%g0,%%g1\n\t" \
+ "jmpl %0, %%o7\n\t" \
+ "restore %%g0,%%g0,%%g0\n\t" \
+ : /*"=r" (status) */ : \
+ "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+ unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv. This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+ "sdiv %2,%3,%%l6\n\t" \
+ "smul %%l6,%3,%%l6\n\t" \
+ "sub %2,%%l6,%0\n\t" \
+ :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name. Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c
new file mode 100644
index 000000000..6f0d9f8fd
--- /dev/null
+++ b/ldso/ldso/sparc/elfinterp.c
@@ -0,0 +1,355 @@
+/* Run an ELF binary on a linux system.
+
+ Copyright (C) 1995, Eric Youngdale.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+#ifdef VERBOSE_DLINKER
+static char * _dl_reltypes[] = { "R_SPARC_NONE", "R_SPARC_8",
+ "R_SPARC_16", "R_SPARC_32", "R_SPARC_DISP8", "R_SPARC_DISP16",
+ "R_SPARC_DISP32", "R_SPARC_WDISP30", "R_SPARC_WDISP22",
+ "R_SPARC_HI22", "R_SPARC_22", "R_SPARC_13", "R_SPARC_LO10",
+ "R_SPARC_GOT10", "R_SPARC_GOT13", "R_SPARC_GOT22", "R_SPARC_PC10",
+ "R_SPARC_PC22", "R_SPARC_WPLT30", "R_SPARC_COPY",
+ "R_SPARC_GLOB_DAT", "R_SPARC_JMP_SLOT", "R_SPARC_RELATIVE",
+ "R_SPARC_UA32"};
+#endif
+
+/* Program to load an ELF binary on a linux system, and run it.
+References to symbols in sharable libraries can be resolved by either
+an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
+ I ever taken any courses on internals. This program was developed using
+ information available through the book "UNIX SYSTEM V RELEASE 4,
+ Programmers guide: Ansi C and Programming Support Tools", which did
+ a more than adequate job of explaining everything required to get this
+ working. */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+/*#include <stdlib.h>*/
+#include "string.h"
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include "hash.h"
+#include "linuxelf.h"
+#include "sysdep.h"
+#include "../syscall.h"
+#include "../string.h"
+
+#define SVR4_COMPATIBILITY
+
+extern char *_dl_progname;
+
+extern _dl_linux_resolve(void);
+
+unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
+{
+ int reloc_type;
+ struct elf32_rela * this_reloc;
+ char * strtab;
+ struct elf32_sym * symtab;
+ struct elf32_rela * rel_addr;
+ struct elf_resolve * tpnt;
+ int symtab_index;
+ char * new_addr;
+ char ** got_addr;
+ unsigned int instr_addr;
+ tpnt = (struct elf_resolve *) plt[2];
+
+ rel_addr = (struct elf32_rela *) (tpnt->dynamic_info[DT_JMPREL] +
+ tpnt->loadaddr);
+
+ /*
+ * Generate the correct relocation index into the .rela.plt section.
+ */
+ reloc_entry = (reloc_entry >> 12) - 0xc;
+
+ this_reloc = (struct elf32_rela *) ((char *) rel_addr + reloc_entry);
+
+ reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+ symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ _dl_fdprintf(2, "tpnt = %x\n", tpnt);
+ _dl_fdprintf(2, "reloc = %x\n", this_reloc);
+ _dl_fdprintf(2, "symtab = %x\n", symtab);
+ _dl_fdprintf(2, "strtab = %x\n", strtab);
+
+
+ if (reloc_type != R_SPARC_JMP_SLOT) {
+ _dl_fdprintf(2, "%s: incorrect relocation type in jump relocations (%d)\n",
+ _dl_progname, reloc_type);
+ _dl_exit(30);
+ };
+
+ /* Address of jump instruction to fix up */
+ instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr);
+ got_addr = (char **) instr_addr;
+
+ _dl_fdprintf(2, "symtab_index %d\n", symtab_index);
+
+#ifdef DEBUG
+ _dl_fdprintf(2, "Resolving symbol %s\n",
+ strtab + symtab[symtab_index].st_name);
+#endif
+
+ /* Get the address of the GOT entry */
+ new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) got_addr, tpnt, 0);
+ if(!new_addr) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_exit(31);
+ };
+/* #define DEBUG_LIBRARY */
+#ifdef DEBUG_LIBRARY
+ if((unsigned int) got_addr < 0x40000000) {
+ _dl_fdprintf(2, "Calling library function: %s\n",
+ strtab + symtab[symtab_index].st_name);
+ } else {
+ got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
+ got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
+ }
+#else
+ got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
+ got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
+#endif
+ _dl_fdprintf(2, "Address = %x\n",new_addr);
+ _dl_exit(32);
+
+ return (unsigned int) new_addr;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type){
+ int i;
+ char * strtab;
+ int reloc_type;
+ int symtab_index;
+ struct elf32_sym * symtab;
+ struct elf32_rela * rpnt;
+ unsigned int * reloc_addr;
+
+ /* Now parse the relocation information */
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i += sizeof(struct elf32_rela), rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+ /* When the dynamic linker bootstrapped itself, it resolved some symbols.
+ Make sure we do not do them again */
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+ if(symtab_index && tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ switch(reloc_type){
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_JMP_SLOT:
+ break;
+ default:
+ _dl_fdprintf(2, "%s: (LAZY) can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if(symtab_index) _dl_fdprintf(2, "'%s'\n",
+ strtab + symtab[symtab_index].st_name);
+ _dl_exit(33);
+ };
+ };
+}
+
+int _dl_parse_relocation_information(struct elf_resolve * tpnt, int rel_addr,
+ int rel_size, int type){
+ int i;
+ char * strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym * symtab;
+ struct elf32_rela * rpnt;
+ unsigned int * reloc_addr;
+ unsigned int symbol_addr;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+
+ if(symtab_index) {
+
+ if(tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ symbol_addr = (unsigned int)
+ _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ tpnt->symbol_scope, (int) reloc_addr,
+ (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), 0);
+
+ if(!symbol_addr &&
+ ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ };
+ };
+ switch(reloc_type){
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_32:
+ *reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+ case R_SPARC_DISP32:
+ *reloc_addr = symbol_addr + rpnt->r_addend - (unsigned int) reloc_addr;
+ break;
+ case R_SPARC_GLOB_DAT:
+ *reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+ case R_SPARC_JMP_SLOT:
+ reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
+ reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
+ break;
+ case R_SPARC_RELATIVE:
+ *reloc_addr += (unsigned int) tpnt->loadaddr + rpnt->r_addend;
+ break;
+ case R_SPARC_HI22:
+ if (!symbol_addr)
+ symbol_addr = tpnt->loadaddr + rpnt->r_addend;
+ else
+ symbol_addr += rpnt->r_addend;
+ *reloc_addr = (*reloc_addr & 0xffc00000)|(symbol_addr >> 10);
+ break;
+ case R_SPARC_LO10:
+ if (!symbol_addr)
+ symbol_addr = tpnt->loadaddr + rpnt->r_addend;
+ else
+ symbol_addr += rpnt->r_addend;
+ *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
+ break;
+ case R_SPARC_WDISP30:
+ *reloc_addr = (*reloc_addr & 0xc0000000)|
+ ((symbol_addr - (unsigned int) reloc_addr) >> 2);
+ break;
+ case R_SPARC_COPY:
+#if 0 /* This one is done later */
+ _dl_fdprintf(2, "Doing copy for symbol ");
+ if(symtab_index) _dl_fdprintf(2, strtab + symtab[symtab_index].st_name);
+ _dl_fdprintf(2, "\n");
+ _dl_memcpy((void *) symtab[symtab_index].st_value,
+ (void *) symbol_addr,
+ symtab[symtab_index].st_size);
+#endif
+ break;
+ default:
+ _dl_fdprintf(2, "%s: can't handle reloc type ", _dl_progname);
+#ifdef VERBOSE_DLINKER
+ _dl_fdprintf(2, "%s ", _dl_reltypes[reloc_type]);
+#endif
+ if (symtab_index)
+ _dl_fdprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
+ _dl_exit(34);
+ };
+
+ };
+ return goof;
+}
+
+
+/* This is done as a separate step, because there are cases where
+ information is first copied and later initialized. This results in
+ the wrong information being copied. Someone at Sun was complaining about
+ a bug in the handling of _COPY by SVr4, and this may in fact be what he
+ was talking about. Sigh. */
+
+/* No, there are cases where the SVr4 linker fails to emit COPY relocs
+ at all */
+
+int _dl_parse_copy_information(struct dyn_elf * xpnt, int rel_addr,
+ int rel_size, int type)
+{
+ int i;
+ char * strtab;
+ int reloc_type;
+ int goof = 0;
+ struct elf32_sym * symtab;
+ struct elf32_rela * rpnt;
+ unsigned int * reloc_addr;
+ unsigned int symbol_addr;
+ struct elf_resolve *tpnt;
+ int symtab_index;
+ /* Now parse the relocation information */
+
+ tpnt = xpnt->dyn;
+
+ rpnt = (struct elf32_rela *) (rel_addr + tpnt->loadaddr);
+
+ symtab = (struct elf32_sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+ strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+ for(i=0; i< rel_size; i+= sizeof(struct elf32_rela), rpnt++){
+ reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
+ if(reloc_type != R_SPARC_COPY) continue;
+ symtab_index = ELF32_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ if(!symtab_index && tpnt->libtype == program_interpreter) continue;
+ if(symtab_index) {
+
+ if(tpnt->libtype == program_interpreter &&
+ _dl_symbol(strtab + symtab[symtab_index].st_name))
+ continue;
+
+ symbol_addr = (unsigned int)
+ _dl_find_hash(strtab + symtab[symtab_index].st_name,
+ xpnt->next, (int) reloc_addr, NULL, 1);
+ if(!symbol_addr) {
+ _dl_fdprintf(2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, strtab + symtab[symtab_index].st_name);
+ goof++;
+ };
+ };
+ if (!goof)
+ _dl_memcpy((char *) symtab[symtab_index].st_value,
+ (char *) symbol_addr,
+ symtab[symtab_index].st_size);
+ };
+ return goof;
+}
+
+
diff --git a/ldso/ldso/sparc/ld_sysdep.h b/ldso/ldso/sparc/ld_sysdep.h
new file mode 100644
index 000000000..1d4c0354f
--- /dev/null
+++ b/ldso/ldso/sparc/ld_sysdep.h
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here. We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT. For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots. The PLT should
+ * look like:
+ *
+ * save %sp, -64, %sp
+ * call _dl_linux_resolve
+ * nop
+ * .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
+ GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+ GOT_BASE[2] = 0x01000000; /* nop */ \
+ GOT_BASE[3] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)) { \
+ case R_SPARC_32: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_GLOB_DAT: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_JMP_SLOT: \
+ REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
+ REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
+ break; \
+ case R_SPARC_NONE: \
+ break; \
+ case R_SPARC_WDISP30: \
+ break; \
+ case R_SPARC_RELATIVE: \
+ *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done. The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START() \
+ __asm__ volatile ( \
+ "add %%g0,%%g0,%%g1\n\t" \
+ "jmpl %0, %%o7\n\t" \
+ "restore %%g0,%%g0,%%g0\n\t" \
+ : /*"=r" (status) */ : \
+ "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+ unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv. This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+ "sdiv %2,%3,%%l6\n\t" \
+ "smul %%l6,%3,%%l6\n\t" \
+ "sub %2,%%l6,%0\n\t" \
+ :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name. Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/resolve.S b/ldso/ldso/sparc/resolve.S
new file mode 100644
index 000000000..ea985b5c8
--- /dev/null
+++ b/ldso/ldso/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/ldso/ldso/sparc/sdiv.S b/ldso/ldso/sparc/sdiv.S
new file mode 100644
index 000000000..5e52e1959
--- /dev/null
+++ b/ldso/ldso/sparc/sdiv.S
@@ -0,0 +1,369 @@
+ /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .div name of function to generate
+ * div div=div => %o0 / %o1; div=rem => %o0 % %o1
+ * true true=true => signed; true=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+
+#include "DEFS.h"
+#ifndef __linux__
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#else
+#include <asm/traps.h>
+#endif
+
+FUNC(_dl_div)
+ ! compute sign of result; if neither is negative, no problem
+ orcc %o1, %o0, %g0 ! either negative?
+ bge 2f ! no, go do the divide
+ xor %o1, %o0, %g6 ! compute sign in any case
+ tst %o1
+ bge 1f
+ tst %o0
+ ! %o1 is definitely negative; %o0 might also be negative
+ bge 2f ! if %o0 not negative...
+ sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
+1: ! %o0 is negative, %o1 is nonnegative
+ sub %g0, %o0, %o0 ! make %o0 nonnegative
+2:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ sub %o2, 1, %o2
+
+
+Lgot_result:
+ ! check to see if answer should be < 0
+ tst %g6
+ bl,a 1f
+ sub %g0, %o2, %o2
+1:
+ retl
+ mov %o2, %o0
diff --git a/ldso/ldso/sparc/sysdep.h b/ldso/ldso/sparc/sysdep.h
new file mode 100644
index 000000000..1d4c0354f
--- /dev/null
+++ b/ldso/ldso/sparc/sysdep.h
@@ -0,0 +1,131 @@
+
+/*
+ * Various assmbly language/system dependent hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+#define LINUXBIN
+
+/*
+ * Define this if the system uses RELOCA.
+ */
+#define ELF_USES_RELOCA
+
+/*
+ * Get the address of the Global offset table. This must be absolute, not
+ * relative.
+ */
+#define GET_GOT(X) __asm__("\tmov %%l7,%0\n\t" : "=r" (X))
+
+/*
+ * Get a pointer to the argv array. On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here. We assume that argc is stored
+ * at the word just below the argvp that we return here.
+ */
+#define GET_ARGV(ARGVP, ARGS) __asm__("\tadd %%fp,68,%0\n" : "=r" (ARGVP));
+
+/*
+ * Initialization sequence for a GOT. For the Sparc, this points to the
+ * PLT, and we need to initialize a couple of the slots. The PLT should
+ * look like:
+ *
+ * save %sp, -64, %sp
+ * call _dl_linux_resolve
+ * nop
+ * .word implementation_dependent
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ GOT_BASE[0] = 0x9de3bfc0; /* save %sp, -64, %sp */ \
+ GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2); \
+ GOT_BASE[2] = 0x01000000; /* nop */ \
+ GOT_BASE[3] = (int) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation. This is only used when
+ * bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \
+ switch(ELF32_R_TYPE((RELP)->r_info)) { \
+ case R_SPARC_32: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_GLOB_DAT: \
+ *REL = SYMBOL + (RELP)->r_addend; \
+ break; \
+ case R_SPARC_JMP_SLOT: \
+ REL[1] = 0x03000000 | ((SYMBOL >> 10) & 0x3fffff); \
+ REL[2] = 0x81c06000 | (SYMBOL & 0x3ff); \
+ break; \
+ case R_SPARC_NONE: \
+ break; \
+ case R_SPARC_WDISP30: \
+ break; \
+ case R_SPARC_RELATIVE: \
+ *REL += (unsigned int) LOAD + (RELP)->r_addend; \
+ break; \
+ default: \
+ _dl_exit(1); \
+ }
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done. The crt calls atexit with $g1 if not null, so we need to
+ * ensure that it contains NULL.
+ */
+
+#define START() \
+ __asm__ volatile ( \
+ "add %%g0,%%g0,%%g1\n\t" \
+ "jmpl %0, %%o7\n\t" \
+ "restore %%g0,%%g0,%%g0\n\t" \
+ : /*"=r" (status) */ : \
+ "r" (_dl_elf_main): "g1", "o0", "o1")
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_SPARC
+#undef MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "Sparc"
+
+#ifndef COMPILE_ASM
+extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
+ unsigned int * i);
+#endif
+
+/*
+ * Define this if you want a dynamic loader that works on Solaris.
+ */
+#define SOLARIS_COMPATIBLE
+
+/*
+ * Define this because we do not want to call .udiv in the library.
+ * Change on the plans -miguel:
+ * We just statically link against .udiv. This is required
+ * if we want to be able to run on Sun4c machines.
+ */
+
+/* We now link .urem against this one */
+#ifdef USE_V8
+#define do_rem(result,n,base) ({ \
+volatile int __res; \
+__asm__("mov %%g0,%%Y\n\t" \
+ "sdiv %2,%3,%%l6\n\t" \
+ "smul %%l6,%3,%%l6\n\t" \
+ "sub %2,%%l6,%0\n\t" \
+ :"=r" (result),"=r" (__res):"r" (n),"r"(base) : "l6" ); __res; })
+#else
+#define do_rem(a,b,c) a = _dl_urem (b,c);
+#endif
+/*
+ * dbx wants the binder to have a specific name. Mustn't disappoint it.
+ */
+#ifdef SOLARIS_COMPATIBLE
+#define _dl_linux_resolve _elf_rtbndr
+#endif
+
diff --git a/ldso/ldso/sparc/udiv.S b/ldso/ldso/sparc/udiv.S
new file mode 100644
index 000000000..df4e5385e
--- /dev/null
+++ b/ldso/ldso/sparc/udiv.S
@@ -0,0 +1,351 @@
+ /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .udiv name of function to generate
+ * div div=div => %o0 / %o1; div=rem => %o0 % %o1
+ * false false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+#include "DEFS.h"
+#ifndef __linux__
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#else
+#include <asm/traps.h>
+#endif
+
+FUNC(_dl_udiv)
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ sub %o2, 1, %o2
+
+
+Lgot_result:
+
+ retl
+ mov %o2, %o0
diff --git a/ldso/ldso/sparc/umul.S b/ldso/ldso/sparc/umul.S
new file mode 100644
index 000000000..7a26c295c
--- /dev/null
+++ b/ldso/ldso/sparc/umul.S
@@ -0,0 +1,153 @@
+/*
+ * Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
+ * upper 32 bits of the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies. Short
+ * multiplies require 25 instruction cycles, and long ones require
+ * 45 instruction cycles.
+ *
+ * On return, overflow has occurred (%o1 is not zero) if and only if
+ * the Z condition code is clear, allowing, e.g., the following:
+ *
+ * call .umul
+ * nop
+ * bnz overflow (or tnz)
+ */
+
+#include "DEFS.h"
+FUNC(.umul)
+ or %o0, %o1, %o4
+ mov %o0, %y ! multiplier -> Y
+ andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args
+ be Lmul_shortway ! if zero, can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
+
+ /*
+ * Long multiply. 32 steps, followed by a final shift step.
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %o1, %o4 ! 13
+ mulscc %o4, %o1, %o4 ! 14
+ mulscc %o4, %o1, %o4 ! 15
+ mulscc %o4, %o1, %o4 ! 16
+ mulscc %o4, %o1, %o4 ! 17
+ mulscc %o4, %o1, %o4 ! 18
+ mulscc %o4, %o1, %o4 ! 19
+ mulscc %o4, %o1, %o4 ! 20
+ mulscc %o4, %o1, %o4 ! 21
+ mulscc %o4, %o1, %o4 ! 22
+ mulscc %o4, %o1, %o4 ! 23
+ mulscc %o4, %o1, %o4 ! 24
+ mulscc %o4, %o1, %o4 ! 25
+ mulscc %o4, %o1, %o4 ! 26
+ mulscc %o4, %o1, %o4 ! 27
+ mulscc %o4, %o1, %o4 ! 28
+ mulscc %o4, %o1, %o4 ! 29
+ mulscc %o4, %o1, %o4 ! 30
+ mulscc %o4, %o1, %o4 ! 31
+ mulscc %o4, %o1, %o4 ! 32
+ mulscc %o4, %g0, %o4 ! final shift
+
+
+ /*
+ * Normally, with the shift-and-add approach, if both numbers are
+ * positive you get the correct result. With 32-bit two's-complement
+ * numbers, -x is represented as
+ *
+ * x 32
+ * ( 2 - ------ ) mod 2 * 2
+ * 32
+ * 2
+ *
+ * (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s,
+ * we can treat this as if the radix point were just to the left
+ * of the sign bit (multiply by 2^32), and get
+ *
+ * -x = (2 - x) mod 2
+ *
+ * Then, ignoring the `mod 2's for convenience:
+ *
+ * x * y = xy
+ * -x * y = 2y - xy
+ * x * -y = 2x - xy
+ * -x * -y = 4 - 2x - 2y + xy
+ *
+ * For signed multiplies, we subtract (x << 32) from the partial
+ * product to fix this problem for negative multipliers (see mul.s).
+ * Because of the way the shift into the partial product is calculated
+ * (N xor V), this term is automatically removed for the multiplicand,
+ * so we don't have to adjust.
+ *
+ * But for unsigned multiplies, the high order bit wasn't a sign bit,
+ * and the correction is wrong. So for unsigned multiplies where the
+ * high order bit is one, we end up with xy - (y << 32). To fix it
+ * we add y << 32.
+ */
+#if 0
+ tst %o1
+ bl,a 1f ! if %o1 < 0 (high order bit = 1),
+ add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half)
+1: rd %y, %o0 ! get lower half of product
+ retl
+ addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0
+#else
+ /* Faster code from tege@sics.se. */
+ sra %o1, 31, %o2 ! make mask from sign bit
+ and %o0, %o2, %o2 ! %o2 = 0 or %o0, depending on sign of %o1
+ rd %y, %o0 ! get lower half of product
+ retl
+ addcc %o4, %o2, %o1 ! add compensation and put upper half in place
+#endif
+
+Lmul_shortway:
+ /*
+ * Short multiply. 12 steps, followed by a final shift step.
+ * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+ * but there is no problem with %o0 being negative (unlike above),
+ * and overflow is impossible (the answer is at most 24 bits long).
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %g0, %o4 ! final shift
+
+ /*
+ * %o4 has 20 of the bits that should be in the result; %y has
+ * the bottom 12 (as %y's top 12). That is:
+ *
+ * %o4 %y
+ * +----------------+----------------+
+ * | -12- | -20- | -12- | -20- |
+ * +------(---------+------)---------+
+ * -----result-----
+ *
+ * The 12 bits of %o4 left of the `result' area are all zero;
+ * in fact, all top 20 bits of %o4 are zero.
+ */
+
+ rd %y, %o5
+ sll %o4, 12, %o0 ! shift middle bits left 12
+ srl %o5, 20, %o5 ! shift low bits right 20
+ or %o5, %o0, %o0
+ retl
+ addcc %g0, %g0, %o1 ! %o1 = zero, and set Z
diff --git a/ldso/ldso/sparc/urem.S b/ldso/ldso/sparc/urem.S
new file mode 100644
index 000000000..8d304038b
--- /dev/null
+++ b/ldso/ldso/sparc/urem.S
@@ -0,0 +1,352 @@
+ /* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .urem name of function to generate
+ * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1
+ * false false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+
+#include "DEFS.h"
+#ifdef __linux__
+#include <asm/traps.h>
+#else
+#ifdef __svr4__
+#include <sys/trap.h>
+#else
+#include "/usr/include/machine/trap.h"
+#endif
+#endif
+
+FUNC(_dl_urem)
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ add %o3, %o1, %o3
+
+
+Lgot_result:
+
+ retl
+ mov %o3, %o0
diff --git a/ldso/ldso/string.h b/ldso/ldso/string.h
new file mode 100644
index 000000000..1ea8fd7ae
--- /dev/null
+++ b/ldso/ldso/string.h
@@ -0,0 +1,112 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h> /* for size_t */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+extern inline char * _dl_strcpy(char * dst,const char *src)
+{
+ register char *ptr = dst;
+
+ while (*src)
+ *dst++ = *src++;
+ *dst = '\0';
+
+ return ptr;
+}
+
+extern inline int _dl_strcmp(const char * s1,const char * s2)
+{
+ unsigned register char c1, c2;
+
+ do {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0')
+ return c1 - c2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+
+extern inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
+{
+ unsigned register char c1 = '\0';
+ unsigned register char c2 = '\0';
+
+ while (len > 0) {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0' || c1 != c2)
+ return c1 - c2;
+ len--;
+ }
+
+ return c1 - c2;
+}
+
+extern inline char * _dl_strchr(const char * str,int c)
+{
+ register char ch;
+
+ do {
+ if ((ch = *str) == c)
+ return (char *) str;
+ str++;
+ }
+ while (ch);
+
+ return 0;
+}
+
+
+extern inline size_t _dl_strlen(const char * str)
+{
+ register char *ptr = (char *) str;
+
+ while (*ptr)
+ ptr++;
+ return (ptr - str);
+}
+
+extern inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+ register char *a = dst;
+ register const char *b = src;
+
+ while (len--)
+ *a++ = *b++;
+
+ return dst;
+}
+
+
+extern inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
+{
+ unsigned char *c1 = (unsigned char *)s1;
+ unsigned char *c2 = (unsigned char *)s2;
+
+ while (len--) {
+ if (*c1 != *c2)
+ return *c1 - *c2;
+ c1++;
+ c2++;
+ }
+ return 0;
+}
+
+extern inline void * _dl_memset(void * str,int c,size_t len)
+{
+ register char *a = str;
+
+ while (len--)
+ *a++ = c;
+
+ return str;
+}
+
+#endif
diff --git a/ldso/ldso/syscall.h b/ldso/ldso/syscall.h
new file mode 100644
index 000000000..3cf244338
--- /dev/null
+++ b/ldso/ldso/syscall.h
@@ -0,0 +1,108 @@
+#include <linux/types.h>
+#include <asm/unistd.h>
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+
+#define _dl_mmap_check_error(__res) \
+ (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+
+
+/* Here are the definitions for some syscalls that are used
+ by the dynamic linker. The idea is that we want to be able
+ to call these before the errno symbol is dynamicly linked, so
+ we use our own version here. Note that we cannot assume any
+ dynamic linking at all, so we cannot return any error codes.
+ We just punt if there is an error. */
+
+/* Do not include unistd.h, so gcc doesn't whine about
+ * _exit returning. It really doesn't return... */
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long buffer[6];
+
+ buffer[0] = (unsigned long) addr;
+ buffer[1] = (unsigned long) size;
+ buffer[2] = (unsigned long) prot;
+ buffer[3] = (unsigned long) flags;
+ buffer[4] = (unsigned long) fd;
+ buffer[5] = (unsigned long) offset;
+ return (void *) _dl_mmap_real(buffer);
+}
+
+#define __NR__dl_open __NR_open
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd,
+ const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd,
+ const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like. It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define __NR__dl_stat __NR_stat
+#define stat kernel_stat
+#define new_stat kernel_stat
+#include <asm/stat.h>
+#undef new_stat
+#undef stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct kernel_stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(gid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+extern inline int _dl_suid_ok(void)
+{
+ uid_t uid, euid, gid, egid;
+
+ uid = _dl_getuid();
+ euid = _dl_geteuid();
+ gid = _dl_getgid();
+ egid = _dl_getegid();
+
+ if(uid == euid && gid == egid)
+ return 1;
+ else
+ return 0;
+}
+
diff --git a/ldso/ldso/vsprintf.c b/ldso/ldso/vsprintf.c
new file mode 100644
index 000000000..48c44e38f
--- /dev/null
+++ b/ldso/ldso/vsprintf.c
@@ -0,0 +1,290 @@
+/*
+ * vsprintf.c
+ *
+ * Copyright (C) 1991-1996 Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdarg.h>
+#include "string.h"
+#include "hash.h"
+#include <linux/unistd.h>
+#include "syscall.h"
+
+/* we use this so that we can do without the ctype library */
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+ int i=0;
+
+ while (is_digit(**s))
+ i = i*10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+#ifndef __sparc__
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+#else
+#define do_div(n,base) _dl_div ((n)/(base))
+#define do_div(n,base) ({ \
+int __res; \
+__res = _dl_urem(((unsigned long) n),(unsigned) base); \
+n = _dl_udiv(((unsigned long) n),(unsigned) base); \
+__res; })
+#endif
+
+#define ADD_CHAR(s,n,c) ( ((n) > 1) ? *(s)++ = (c), (n)-- : (c) )
+
+static char * number(char * str, int *bufsize, long num, int base, int size, int precision
+ ,int type)
+{
+ char c,sign,tmp[66];
+ const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+ int i;
+
+ if (type & LARGE)
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if (num < 0) {
+ sign = '-';
+ num = -num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT)))
+ while(size-->0)
+ ADD_CHAR(str, *bufsize, ' ');
+ if (sign)
+ ADD_CHAR(str, *bufsize, sign);
+ if (type & SPECIAL) {
+ if (base==8)
+ ADD_CHAR(str, *bufsize, '0');
+ else if (base==16) {
+ ADD_CHAR(str, *bufsize, '0');
+ ADD_CHAR(str, *bufsize, digits[33]);
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ ADD_CHAR(str, *bufsize, c);
+ while (i < precision--)
+ ADD_CHAR(str, *bufsize, '0');
+ while (i-- > 0)
+ ADD_CHAR(str, *bufsize, tmp[i]);
+ while (size-- > 0)
+ ADD_CHAR(str, *bufsize, ' ');
+ return str;
+}
+
+int _dl_fdprintf(int fd, const char *fmt, ...)
+{
+ int len;
+ unsigned long num;
+ int i, base;
+ char * str;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ int bufsize;
+ char buf[2048];
+ va_list(args);
+
+ va_start(args, fmt);
+
+ for (str=buf, bufsize=sizeof buf ; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ ADD_CHAR(str, bufsize, *fmt);
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (is_digit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (is_digit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ ADD_CHAR(str, bufsize, ' ');
+ ADD_CHAR(str, bufsize, (unsigned char) va_arg(args, int));
+ while (--field_width > 0)
+ ADD_CHAR(str, bufsize, ' ');
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s)
+ s = "<NULL>";
+
+ len = _dl_strlen(s);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ ADD_CHAR(str, bufsize, ' ');
+ for (i = 0; i < len; ++i)
+ ADD_CHAR(str, bufsize, *s++);
+ while (len < field_width--)
+ ADD_CHAR(str, bufsize, ' ');
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str, &bufsize,
+ (unsigned long) va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+
+ case 'n':
+ if (qualifier == 'l') {
+ long * ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else {
+ int * ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ if (*fmt != '%')
+ ADD_CHAR(str, bufsize, '%');
+ if (*fmt)
+ ADD_CHAR(str, bufsize, *fmt);
+ else
+ --fmt;
+ continue;
+ }
+ if (qualifier == 'l')
+ num = va_arg(args, unsigned long);
+ else if (qualifier == 'h')
+ if (flags & SIGN)
+ num = va_arg(args, short);
+ else
+ num = va_arg(args, unsigned short);
+ else if (flags & SIGN)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ str = number(str, &bufsize, num, base, field_width, precision, flags);
+ }
+ *str = '\0';
+ _dl_write(fd, buf, str-buf);
+ return str-buf;
+}
+