Browse Source

Merge the arm port into the main tree. The final version (the one that
actually works) is the most excellent work of Shane Nay <shane@minirl.com>, who
took what I had been doing and fixed it.

Eric Andersen 23 years ago
parent
commit
ecb79165c1

+ 124 - 0
ldso/ldso/arm/dl-syscalls.h

@@ -0,0 +1,124 @@
+#include <sys/types.h>
+
+/*
+ * This file contains the system call macros and syscall 
+ * numbers used by the shared library loader.
+ */
+
+#define __NR_SYSCALL_BASE	0x900000
+
+#define __NR_exit			(__NR_SYSCALL_BASE+  1)
+#define __NR_read			(__NR_SYSCALL_BASE+  3)
+#define __NR_write			(__NR_SYSCALL_BASE+  4)
+#define __NR_open			(__NR_SYSCALL_BASE+  5)
+#define __NR_close			(__NR_SYSCALL_BASE+  6)
+#define __NR_getuid			(__NR_SYSCALL_BASE+ 24)
+#define __NR_geteuid			(__NR_SYSCALL_BASE+ 49)
+#define __NR_getgid			(__NR_SYSCALL_BASE+ 47)
+#define __NR_getegid			(__NR_SYSCALL_BASE+ 50)
+#define __NR_mmap			(__NR_SYSCALL_BASE+ 90)
+#define __NR_munmap			(__NR_SYSCALL_BASE+ 91)
+#define __NR_stat			(__NR_SYSCALL_BASE+106)
+#define __NR_mprotect			(__NR_SYSCALL_BASE+125)
+
+
+/* Here are the macros which define how this platform makes
+ * system calls.  This particular variant does _not_ set 
+ * errno (note how it is disabled in __syscall_return) since
+ * these will get called before the errno symbol is dynamicly 
+ * linked. */
+
+/* These are Erik's versions of the syscall routines.  His were
+ * cleaner than mine, so I adopted them instead with some
+ * reformating.  Shane Nay.
+ */
+
+#define __sys2(x) #x
+#define __sys1(x) __sys2(x)
+
+#ifndef __syscall
+#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
+#endif
+
+#undef __syscall_return
+#define __syscall_return(type, res)					\
+do {									\
+	if ((unsigned long)(res) >= (unsigned long)(-125)) {		\
+		/*errno = -(res);*/					\
+		res = -1;						\
+	}								\
+	return (type) (res);						\
+} while (0)
+
+#define _syscall0(type,name)						\
+type name(void) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+  "mov %0,r0"								\
+  :"=r" (__res) : : "r0","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  __syscall(name)							\
+  "mov %0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1))						\
+	: "r0","lr");							\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1,type2 arg2) {					\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2))				\
+	: "r0","r1","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1,type2 arg2,type3 arg3) {				\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3))	\
+        : "r0","r1","r2","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#undef _syscall4
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {		\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  "mov\tr3,%4\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+  	: "=r" (__res)							\
+  	: "r" ((long)(arg1)),"r" ((long)(arg2)),                        \
+	  "r" ((long)(arg3)),"r" ((long)(arg4))	                        \
+  	: "r0","r1","r2","r3","lr");					\
+  __syscall_return(type,__res);						\
+}
+  
+

+ 120 - 0
ldso/ldso/arm/dl-sysdep.h

@@ -0,0 +1,120 @@
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/* 
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*)   ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{				\
+  GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
+  GOT_BASE[1] = (unsigned long) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)		\
+	switch(ELF32_R_TYPE((RELP)->r_info)){			\
+	case R_ARM_ABS32:					\
+	  *REL += SYMBOL;					\
+	  break;						\
+        case R_ARM_PC24:					\
+          {							\
+	    unsigned long newval, topbits;			\
+	    long addend=*REL & 0x00ffffff;			\
+	    if(addend & 0x00800000)				\
+	      addend|=0xff000000;				\
+	    newval=SYMBOL- ((unsigned long)REL) + (addend<<2);	\
+	    topbits=newval & 0xfe000000;			\
+	    if (topbits != 0xfe000000 && topbits != 0x00000000) {/* \
+	      newval=fix_bad_pc24(REL,value) -			\
+	      ((unsigned long)REL) + (addend << 2);		\
+	      topbits=newval & 0xfe000000;			\
+	      if(topbits != 0xfe000000 && topbits != 0x00000000)*/ \
+	        _dl_exit(1);					\
+	    }							\
+	    newval>>=2;						\
+	    SYMBOL= (*REL & 0xff000000)|(newval & 0x00ffffff);	\
+	    *REL=SYMBOL;					\
+	  }							\
+	  break;						\
+	case R_ARM_GLOB_DAT:					\
+	case R_ARM_JUMP_SLOT:					\
+	  *REL = SYMBOL;					\
+	  break;						\
+        case R_ARM_RELATIVE:					\
+	  *REL += (unsigned long) LOAD;				\
+	  break;						\
+        case R_ARM_NONE:					\
+	  break;						\
+	default:						\
+	  _dl_exit(1);						\
+	}
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  This routine has to exit the current function, then 
+ * call the _dl_elf_main function.
+ */
+
+#define START()   return _dl_elf_main;      
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_ARM
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "ARM"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+
+static inline unsigned long arm_modulus(unsigned long m, unsigned long p) {
+	unsigned long i,t,inc;
+        i=p; t=0;
+        while(!(i&(1<<31))) {
+                i<<=1;
+                t++;
+        }
+        t--;
+        for(inc=t;inc>2;inc--) {
+                i=p<<inc;
+                if(i&(1<<31))
+                        break;
+                while(m>=i) {
+                        m-=i;
+                        i<<=1;
+                        if(i&(1<<31))
+                                break;
+                        if(i<p)
+                                break;
+                }
+        }
+        while(m>=p) {
+                m-=p;
+        }
+        return m;
+}
+
+#define do_rem(result, n, base)  result=arm_modulus(n,base);

+ 374 - 0
ldso/ldso/arm/elfinterp.c

@@ -0,0 +1,374 @@
+/* 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_ARM_NONE", "R_ARM_PC24", "R_ARM_ABS32", "R_ARM_REL32",
+	"R_ARM_PC13", "R_ARM_ABS16", "R_ARM_ABS12", "R_ARM_THM_ABS5",
+	"R_ARM_ABS8", "R_ARM_SBREL32", "R_ARM_THM_PC22", "R_ARM_THM_PC8",
+	"R_ARM_AMP_VCALL9", "R_ARM_SWI24", "R_ARM_THM_SWI8", "R_ARM_XPC25",
+	"R_ARM_THM_XPC22", "R_ARM_COPY", "R_ARM_GLOB_DAT", "R_ARM_JUMP_SLOT",
+	"R_ARM_RELATIVE", "R_ARM_GOTOFF", "R_ARM_GOTPC", "R_ARM_GOT32",
+	"R_ARM_PLT32", "R_ARM_ALU_PCREL_7_0", "R_ARM_ALU_PCREL_15_8",
+	"R_ARM_ALU_PCREL_23_15", "R_ARM_LDR_SBREL_11_0", "R_ARM_ALU_SBREL_19_12",
+	"R_ARM_ALU_SBREL_27_20", "R_ARM_GNU_VTENTRY", "R_ARM_GNU_VTINHERIT",
+	"R_ARM_THM_PC11", "R_ARM_THM_PC9", "R_ARM_RXPC25", "R_ARM_RSBREL32",
+	"R_ARM_THM_RPC22", "R_ARM_RREL32", "R_ARM_RABS22", "R_ARM_RPC24",
+	"R_ARM_RBASE", "R_ARM_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 "elf.h"
+#include "hash.h"
+#include "syscall.h"
+#include "string.h"
+#include "sysdep.h"
+
+extern char *_dl_progname;
+
+extern int _dl_linux_resolve(void);
+
+unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
+{
+	int reloc_type;
+	Elf32_Rel *this_reloc;
+	char *strtab;
+	Elf32_Sym *symtab;
+	Elf32_Rel *rel_addr;
+	int symtab_index;
+	char *new_addr;
+	char **got_addr;
+	unsigned long instr_addr;
+
+	rel_addr = (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 = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+	if (reloc_type != R_ARM_JUMP_SLOT) {
+	  _dl_fdprintf(2, "%s: Incorrect relocation type in jump relocations\n", 
+		       _dl_progname);
+	  _dl_exit(1);
+	};
+	
+	/* Address of jump instruction to fix up */
+	instr_addr = ((unsigned long) this_reloc->r_offset + 
+			(unsigned long) tpnt->loadaddr);
+	got_addr = (char **) instr_addr;
+
+#ifdef DL_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, (unsigned long) 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);
+	};
+#ifdef DL_DEBUG
+	if ((unsigned long) 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 long) new_addr;
+}
+
+void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, 
+	unsigned long rel_addr, unsigned long rel_size, int type)
+{
+	int i;
+	char *strtab;
+	int reloc_type;
+	int symtab_index;
+	Elf32_Sym *symtab;
+	Elf32_Rel *rpnt;
+	unsigned long *reloc_addr;
+
+	/* Now parse the relocation information */
+	rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(Elf32_Rel);
+
+	symtab =
+		(Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+	for (i = 0; i < rel_size; i++, rpnt++) {
+		reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
+		reloc_type = ELF32_R_TYPE(rpnt->r_info);
+		symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+		/* 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_ARM_NONE:
+			break;
+		case R_ARM_JUMP_SLOT:
+			*reloc_addr += (unsigned long) 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);
+		};
+	};
+}
+
+static unsigned long
+fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
+{
+  static void *fix_page;
+  static unsigned int fix_offset;
+  unsigned int *fix_address;
+  if (! fix_page)
+    {
+      fix_page = _dl_mmap (NULL,  4096   , PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      fix_offset = 0;
+    }
+
+  fix_address = (unsigned int *)(fix_page + fix_offset);
+  fix_address[0] = 0xe51ff004;  /* ldr pc, [pc, #-4] */
+  fix_address[1] = value;
+
+  fix_offset += 8;
+  if (fix_offset >= 4096)
+    fix_page = NULL;
+
+  return (unsigned long)fix_address;
+}
+
+
+int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
+	unsigned long rel_addr, unsigned long rel_size, int type)
+{
+	int i;
+	char *strtab;
+	int reloc_type;
+	int goof = 0;
+	Elf32_Sym *symtab;
+	Elf32_Rel *rpnt;
+	unsigned long *reloc_addr;
+	unsigned long symbol_addr;
+	int symtab_index;
+
+	/* Now parse the relocation information */
+
+	rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(Elf32_Rel);
+
+	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+	for (i = 0; i < rel_size; i++, rpnt++) {
+		reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
+		reloc_type = ELF32_R_TYPE(rpnt->r_info);
+		symtab_index = ELF32_R_SYM(rpnt->r_info);
+		symbol_addr = 0;
+
+		if (!symtab_index && tpnt->libtype == program_interpreter)
+			continue;
+
+		if (symtab_index) {
+
+			if (tpnt->libtype == program_interpreter &&
+					_dl_symbol(strtab + symtab[symtab_index].st_name))
+				continue;
+
+			symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, 
+					tpnt->symbol_scope, (unsigned long) reloc_addr, 
+					(reloc_type == R_ARM_JUMP_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_ARM_NONE:
+				break;
+			case R_ARM_ABS32:
+				*reloc_addr += symbol_addr;
+				break;
+			case R_ARM_PC24:
+				{
+					unsigned long addend;
+					long newvalue, topbits;
+
+					addend = *reloc_addr & 0x00ffffff;
+					if (addend & 0x00800000) addend |= 0xff000000;
+
+					newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
+					topbits = newvalue & 0xfe000000;
+					if (topbits != 0xfe000000 && topbits != 0x00000000)
+					{
+						newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
+							- (unsigned long)reloc_addr + (addend << 2);
+						topbits = newvalue & 0xfe000000;
+						if (topbits != 0xfe000000 && topbits != 0x00000000)
+						{
+							_dl_fdprintf(2, "R_ARM_PC24 relocation out of range ");
+							_dl_exit(1);
+						}
+					}
+					newvalue >>= 2;
+					symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
+					*reloc_addr = symbol_addr;
+					break;
+				}
+			case R_ARM_GLOB_DAT:
+			case R_ARM_JUMP_SLOT:
+				*reloc_addr = symbol_addr;
+				break;
+			case R_ARM_RELATIVE:
+				*reloc_addr += (unsigned long) tpnt->loadaddr;
+				break;
+			case R_ARM_COPY:						
+#if 0							
+				/* Do this later */
+				_dl_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, unsigned long rel_addr, 
+	unsigned long rel_size, int type)
+{
+	int i;
+	char *strtab;
+	int reloc_type;
+	int goof = 0;
+	Elf32_Sym *symtab;
+	Elf32_Rel *rpnt;
+	unsigned long *reloc_addr;
+	unsigned long symbol_addr;
+	struct elf_resolve *tpnt;
+	int symtab_index;
+
+	/* Now parse the relocation information */
+
+	tpnt = xpnt->dyn;
+
+	rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(Elf32_Rel);
+
+	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
+	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+
+	for (i = 0; i < rel_size; i++, rpnt++) {
+		reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
+		reloc_type = ELF32_R_TYPE(rpnt->r_info);
+		if (reloc_type != R_ARM_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 long) _dl_find_hash(strtab + 
+				symtab[symtab_index].st_name, xpnt->next, 
+				(unsigned long) 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;
+}

+ 124 - 0
ldso/ldso/arm/ld_syscalls.h

@@ -0,0 +1,124 @@
+#include <sys/types.h>
+
+/*
+ * This file contains the system call macros and syscall 
+ * numbers used by the shared library loader.
+ */
+
+#define __NR_SYSCALL_BASE	0x900000
+
+#define __NR_exit			(__NR_SYSCALL_BASE+  1)
+#define __NR_read			(__NR_SYSCALL_BASE+  3)
+#define __NR_write			(__NR_SYSCALL_BASE+  4)
+#define __NR_open			(__NR_SYSCALL_BASE+  5)
+#define __NR_close			(__NR_SYSCALL_BASE+  6)
+#define __NR_getuid			(__NR_SYSCALL_BASE+ 24)
+#define __NR_geteuid			(__NR_SYSCALL_BASE+ 49)
+#define __NR_getgid			(__NR_SYSCALL_BASE+ 47)
+#define __NR_getegid			(__NR_SYSCALL_BASE+ 50)
+#define __NR_mmap			(__NR_SYSCALL_BASE+ 90)
+#define __NR_munmap			(__NR_SYSCALL_BASE+ 91)
+#define __NR_stat			(__NR_SYSCALL_BASE+106)
+#define __NR_mprotect			(__NR_SYSCALL_BASE+125)
+
+
+/* Here are the macros which define how this platform makes
+ * system calls.  This particular variant does _not_ set 
+ * errno (note how it is disabled in __syscall_return) since
+ * these will get called before the errno symbol is dynamicly 
+ * linked. */
+
+/* These are Erik's versions of the syscall routines.  His were
+ * cleaner than mine, so I adopted them instead with some
+ * reformating.  Shane Nay.
+ */
+
+#define __sys2(x) #x
+#define __sys1(x) __sys2(x)
+
+#ifndef __syscall
+#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
+#endif
+
+#undef __syscall_return
+#define __syscall_return(type, res)					\
+do {									\
+	if ((unsigned long)(res) >= (unsigned long)(-125)) {		\
+		/*errno = -(res);*/					\
+		res = -1;						\
+	}								\
+	return (type) (res);						\
+} while (0)
+
+#define _syscall0(type,name)						\
+type name(void) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+  "mov %0,r0"								\
+  :"=r" (__res) : : "r0","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  __syscall(name)							\
+  "mov %0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1))						\
+	: "r0","lr");							\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1,type2 arg2) {					\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2))				\
+	: "r0","r1","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1,type2 arg2,type3 arg3) {				\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3))	\
+        : "r0","r1","r2","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#undef _syscall4
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {		\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  "mov\tr3,%4\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+  	: "=r" (__res)							\
+  	: "r" ((long)(arg1)),"r" ((long)(arg2)),                        \
+	  "r" ((long)(arg3)),"r" ((long)(arg4))	                        \
+  	: "r0","r1","r2","r3","lr");					\
+  __syscall_return(type,__res);						\
+}
+  
+

+ 120 - 0
ldso/ldso/arm/ld_sysdep.h

@@ -0,0 +1,120 @@
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/* 
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*)   ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{				\
+  GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
+  GOT_BASE[1] = (unsigned long) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)		\
+	switch(ELF32_R_TYPE((RELP)->r_info)){			\
+	case R_ARM_ABS32:					\
+	  *REL += SYMBOL;					\
+	  break;						\
+        case R_ARM_PC24:					\
+          {							\
+	    unsigned long newval, topbits;			\
+	    long addend=*REL & 0x00ffffff;			\
+	    if(addend & 0x00800000)				\
+	      addend|=0xff000000;				\
+	    newval=SYMBOL- ((unsigned long)REL) + (addend<<2);	\
+	    topbits=newval & 0xfe000000;			\
+	    if (topbits != 0xfe000000 && topbits != 0x00000000) {/* \
+	      newval=fix_bad_pc24(REL,value) -			\
+	      ((unsigned long)REL) + (addend << 2);		\
+	      topbits=newval & 0xfe000000;			\
+	      if(topbits != 0xfe000000 && topbits != 0x00000000)*/ \
+	        _dl_exit(1);					\
+	    }							\
+	    newval>>=2;						\
+	    SYMBOL= (*REL & 0xff000000)|(newval & 0x00ffffff);	\
+	    *REL=SYMBOL;					\
+	  }							\
+	  break;						\
+	case R_ARM_GLOB_DAT:					\
+	case R_ARM_JUMP_SLOT:					\
+	  *REL = SYMBOL;					\
+	  break;						\
+        case R_ARM_RELATIVE:					\
+	  *REL += (unsigned long) LOAD;				\
+	  break;						\
+        case R_ARM_NONE:					\
+	  break;						\
+	default:						\
+	  _dl_exit(1);						\
+	}
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  This routine has to exit the current function, then 
+ * call the _dl_elf_main function.
+ */
+
+#define START()   return _dl_elf_main;      
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_ARM
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "ARM"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+
+static inline unsigned long arm_modulus(unsigned long m, unsigned long p) {
+	unsigned long i,t,inc;
+        i=p; t=0;
+        while(!(i&(1<<31))) {
+                i<<=1;
+                t++;
+        }
+        t--;
+        for(inc=t;inc>2;inc--) {
+                i=p<<inc;
+                if(i&(1<<31))
+                        break;
+                while(m>=i) {
+                        m-=i;
+                        i<<=1;
+                        if(i&(1<<31))
+                                break;
+                        if(i<p)
+                                break;
+                }
+        }
+        while(m>=p) {
+                m-=p;
+        }
+        return m;
+}
+
+#define do_rem(result, n, base)  result=arm_modulus(n,base);

+ 41 - 0
ldso/ldso/arm/resolve.S

@@ -0,0 +1,41 @@
+/*
+ * This function is _not_ called directly.  It is jumped to (so no return
+ * address is on the stack) when attempting to use a symbol that has not yet
+ * been resolved.  The first time a jump symbol (such as a function call inside
+ * a shared library) is used (before it gets resolved) it will jump here to
+ * _dl_linux_resolve.  When we get called the stack looks like this:
+ *	reloc_entry
+ *	tpnt
+ *
+ * This function saves all the registers, puts a copy of reloc_entry and tpnt
+ * on the stack (as function arguments) then make the function call
+ * _dl_linux_resolver(tpnt, reloc_entry).  _dl_linux_resolver() figures out
+ * where the jump symbol is _really_ supposed to have jumped to and returns
+ * that to us.  Once we have that, we overwrite tpnt with this fixed up
+ * address. We then clean up after ourselves, put all the registers back how we
+ * found them, then we jump to where the fixed up address, which is where the
+ * jump symbol that got us here really wanted to jump to in the first place.
+ * found them, then we jump to the fixed up address, which is where the jump
+ * symbol that got us here really wanted to jump to in the first place.  
+ *  -Erik Andersen
+ */
+.text
+.globl _dl_linux_resolve
+.type _dl_linux_resolve,#function
+.align 2
+_dl_linux_resolve:
+	stmdb sp!,{r0-r3,sl,fp}
+	sub r1, ip, lr
+	sub r1, r1, #4
+	add r1, r1, r1
+	ldr r0, [lr, #-4]
+	mov r3,r0
+
+	bl _dl_linux_resolver
+
+//	str r0, [lr, #-4]
+	mov ip, r0
+	ldmia sp!,{r0-r3,sl,fp,lr}
+	mov pc,ip
+.size _dl_linux_resolve, .-_dl_linux_resolve
+

+ 124 - 0
ldso/ldso/arm/syscalls.h

@@ -0,0 +1,124 @@
+#include <sys/types.h>
+
+/*
+ * This file contains the system call macros and syscall 
+ * numbers used by the shared library loader.
+ */
+
+#define __NR_SYSCALL_BASE	0x900000
+
+#define __NR_exit			(__NR_SYSCALL_BASE+  1)
+#define __NR_read			(__NR_SYSCALL_BASE+  3)
+#define __NR_write			(__NR_SYSCALL_BASE+  4)
+#define __NR_open			(__NR_SYSCALL_BASE+  5)
+#define __NR_close			(__NR_SYSCALL_BASE+  6)
+#define __NR_getuid			(__NR_SYSCALL_BASE+ 24)
+#define __NR_geteuid			(__NR_SYSCALL_BASE+ 49)
+#define __NR_getgid			(__NR_SYSCALL_BASE+ 47)
+#define __NR_getegid			(__NR_SYSCALL_BASE+ 50)
+#define __NR_mmap			(__NR_SYSCALL_BASE+ 90)
+#define __NR_munmap			(__NR_SYSCALL_BASE+ 91)
+#define __NR_stat			(__NR_SYSCALL_BASE+106)
+#define __NR_mprotect			(__NR_SYSCALL_BASE+125)
+
+
+/* Here are the macros which define how this platform makes
+ * system calls.  This particular variant does _not_ set 
+ * errno (note how it is disabled in __syscall_return) since
+ * these will get called before the errno symbol is dynamicly 
+ * linked. */
+
+/* These are Erik's versions of the syscall routines.  His were
+ * cleaner than mine, so I adopted them instead with some
+ * reformating.  Shane Nay.
+ */
+
+#define __sys2(x) #x
+#define __sys1(x) __sys2(x)
+
+#ifndef __syscall
+#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
+#endif
+
+#undef __syscall_return
+#define __syscall_return(type, res)					\
+do {									\
+	if ((unsigned long)(res) >= (unsigned long)(-125)) {		\
+		/*errno = -(res);*/					\
+		res = -1;						\
+	}								\
+	return (type) (res);						\
+} while (0)
+
+#define _syscall0(type,name)						\
+type name(void) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+  "mov %0,r0"								\
+  :"=r" (__res) : : "r0","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall1(type,name,type1,arg1)					\
+type name(type1 arg1) {							\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  __syscall(name)							\
+  "mov %0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1))						\
+	: "r0","lr");							\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)			\
+type name(type1 arg1,type2 arg2) {					\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2))				\
+	: "r0","r1","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
+type name(type1 arg1,type2 arg2,type3 arg3) {				\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+        : "=r" (__res)							\
+        : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3))	\
+        : "r0","r1","r2","lr");						\
+  __syscall_return(type,__res);						\
+}
+
+#undef _syscall4
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {		\
+  long __res;								\
+  __asm__ __volatile__ (						\
+  "mov\tr0,%1\n\t"							\
+  "mov\tr1,%2\n\t"							\
+  "mov\tr2,%3\n\t"							\
+  "mov\tr3,%4\n\t"							\
+  __syscall(name)							\
+  "mov\t%0,r0"								\
+  	: "=r" (__res)							\
+  	: "r" ((long)(arg1)),"r" ((long)(arg2)),                        \
+	  "r" ((long)(arg3)),"r" ((long)(arg4))	                        \
+  	: "r0","r1","r2","r3","lr");					\
+  __syscall_return(type,__res);						\
+}
+  
+

+ 120 - 0
ldso/ldso/arm/sysdep.h

@@ -0,0 +1,120 @@
+/*
+ * Various assmbly language/system dependent  hacks that are required
+ * so that we can minimize the amount of platform specific code.
+ */
+
+/* 
+ * Define this if the system uses RELOCA.
+ */
+#undef ELF_USES_RELOCA
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address if the first argument, on other platforms we need to
+ * do something a little more subtle here.
+ */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*)   ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) \
+{				\
+  GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
+  GOT_BASE[1] = (unsigned long) MODULE; \
+}
+
+/*
+ * Here is a macro to perform a relocation.  This is only used when
+ * bootstrapping the dynamic loader.  RELP is the relocation that we
+ * are performing, REL is the pointer to the address we are relocating.
+ * SYMBOL is the symbol involved in the relocation, and LOAD is the
+ * load address.
+ */
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)		\
+	switch(ELF32_R_TYPE((RELP)->r_info)){			\
+	case R_ARM_ABS32:					\
+	  *REL += SYMBOL;					\
+	  break;						\
+        case R_ARM_PC24:					\
+          {							\
+	    unsigned long newval, topbits;			\
+	    long addend=*REL & 0x00ffffff;			\
+	    if(addend & 0x00800000)				\
+	      addend|=0xff000000;				\
+	    newval=SYMBOL- ((unsigned long)REL) + (addend<<2);	\
+	    topbits=newval & 0xfe000000;			\
+	    if (topbits != 0xfe000000 && topbits != 0x00000000) {/* \
+	      newval=fix_bad_pc24(REL,value) -			\
+	      ((unsigned long)REL) + (addend << 2);		\
+	      topbits=newval & 0xfe000000;			\
+	      if(topbits != 0xfe000000 && topbits != 0x00000000)*/ \
+	        _dl_exit(1);					\
+	    }							\
+	    newval>>=2;						\
+	    SYMBOL= (*REL & 0xff000000)|(newval & 0x00ffffff);	\
+	    *REL=SYMBOL;					\
+	  }							\
+	  break;						\
+	case R_ARM_GLOB_DAT:					\
+	case R_ARM_JUMP_SLOT:					\
+	  *REL = SYMBOL;					\
+	  break;						\
+        case R_ARM_RELATIVE:					\
+	  *REL += (unsigned long) LOAD;				\
+	  break;						\
+        case R_ARM_NONE:					\
+	  break;						\
+	default:						\
+	  _dl_exit(1);						\
+	}
+
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  This routine has to exit the current function, then 
+ * call the _dl_elf_main function.
+ */
+
+#define START()   return _dl_elf_main;      
+
+
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_ARM
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "ARM"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+
+static inline unsigned long arm_modulus(unsigned long m, unsigned long p) {
+	unsigned long i,t,inc;
+        i=p; t=0;
+        while(!(i&(1<<31))) {
+                i<<=1;
+                t++;
+        }
+        t--;
+        for(inc=t;inc>2;inc--) {
+                i=p<<inc;
+                if(i&(1<<31))
+                        break;
+                while(m>=i) {
+                        m-=i;
+                        i<<=1;
+                        if(i&(1<<31))
+                                break;
+                        if(i<p)
+                                break;
+                }
+        }
+        while(m>=p) {
+                m-=p;
+        }
+        return m;
+}
+
+#define do_rem(result, n, base)  result=arm_modulus(n,base);