Browse Source

Initial version of the dynamic linker code for the CRIS port.

Tobias Anderberg 22 years ago
parent
commit
27ef349611

+ 17 - 0
ldso/ldso/cris/boot1_arch.h

@@ -0,0 +1,17 @@
+/*
+ * This code fix the stack pointer so that the dunamic linker
+ * can find argc, argv and auxvt (Auxillary Vector Table).
+ */
+asm("\
+	.text
+	.globl _dl_boot
+	.type _dl_boot,@function
+_dl_boot:
+	move.d $sp,$r10
+	move.d $pc,$r9
+	add.d _dl_boot2 - ., $r9
+	jsr $r9
+");
+
+#define _dl_boot _dl_boot2
+#define LD_BOOT(X) static void __attribute__ ((unused)) _dl_boot(X)

+ 17 - 0
ldso/ldso/cris/dl-startup.h

@@ -0,0 +1,17 @@
+/*
+ * This code fix the stack pointer so that the dunamic linker
+ * can find argc, argv and auxvt (Auxillary Vector Table).
+ */
+asm("\
+	.text
+	.globl _dl_boot
+	.type _dl_boot,@function
+_dl_boot:
+	move.d $sp,$r10
+	move.d $pc,$r9
+	add.d _dl_boot2 - ., $r9
+	jsr $r9
+");
+
+#define _dl_boot _dl_boot2
+#define LD_BOOT(X) static void __attribute__ ((unused)) _dl_boot(X)

+ 137 - 0
ldso/ldso/cris/dl-syscalls.h

@@ -0,0 +1,137 @@
+/*
+ * This file contains the system call macros and syscall
+ * numbers used by the shared library loader. Taken from
+ * Linux/CRIS 2.4.17 version kernel.
+ */
+
+#define __NR_exit                 1
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_getpid              20
+#define __NR_getuid              24
+#define __NR_getgid              47
+#define __NR_geteuid             49
+#define __NR_getegid             50
+#define __NR_readlink            85
+#define __NR_mmap                90
+#define __NR_munmap              91
+#define __NR_stat               106
+#define __NR_mprotect           125
+
+/* 
+ * Here are the macros which define how this platform makes
+ * system calls.  This particular variant does _not_ set 
+ * errno since these will get called before the errno symbol 
+ * is dynamicly linked. 
+ */
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+  register long __a __asm__ ("r10"); \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1,type2 arg2) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+} 
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+          type5,arg5) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("move %6,$mof\n\t" \
+                        "movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d), "g" (arg5) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+          type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
+                        "movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
+                        : "r10", "r9", "srp"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}

+ 111 - 0
ldso/ldso/cris/dl-sysdep.h

@@ -0,0 +1,111 @@
+/* CRIS can never use Elf32_Rel relocations. */
+#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 long *) ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) 				\
+{                               				\
+	 GOT_BASE[1] = (unsigned long) MODULE; 			\
+	 GOT_BASE[2] = (unsigned long) _dl_linux_resolve; 	\
+} 
+
+/*
+ * 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_CRIS_GLOB_DAT:						\
+		case R_CRIS_JUMP_SLOT:						\
+		case R_CRIS_32:							\
+			*REL = SYMBOL;						\
+			break;							\
+		case R_CRIS_16_PCREL:						\
+			*(short *) *REL = SYMBOL + (RELP)->r_addend - *REL - 2;	\
+			break;							\
+		case R_CRIS_32_PCREL:						\
+			*REL = SYMBOL + (RELP)->r_addend - *REL - 4;		\
+			break;							\
+		case R_CRIS_NONE:						\
+			break;							\
+		case R_CRIS_RELATIVE:						\
+			*REL = (unsigned long) LOAD + (RELP)->r_addend;		\
+			break;							\
+		default:							\
+			_dl_exit(1);						\
+			break;							\
+	} 
+
+/*
+ * Transfer control to the user's application once the dynamic loader
+ * is done. This routine has to exit the current function, then call
+ * _dl_elf_main.
+ */
+#define START() __asm__ volatile ("moveq 0,$r8\n\t
+								   move $r8,$srp\n\t
+								   move.d %1,$sp\n\t
+								   jump %0\n\t" : : "r" (_dl_elf_main), "r" (args))
+
+/* Defined some magic numbers that this ld.so should accept. */
+#define MAGIC1 EM_CRIS
+#undef MAGIC2
+#define ELF_TARGET "CRIS"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry);
+
+/* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
+static inline unsigned long 
+cris_mod(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 = cris_mod(n, base);
+
+/* 8192 bytes alignment */
+#define PAGE_ALIGN 0xffffe000
+#define ADDR_ALIGN 0x1fff
+#define OFFS_ALIGN 0xffffe000

+ 401 - 0
ldso/ldso/cris/elfinterp.c

@@ -0,0 +1,401 @@
+/*
+ * CRIS ELF shared library loader support.
+ *
+ * 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.
+ *
+ * Copyright (C) 2002, Axis Communications AB
+ * All rights reserved
+ *
+ * Author: Tobias Anderberg, <tobiasa@axis.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef VERBOSE_DLINKER
+#define VERBOSE_DLINKER
+#endif
+
+/* Support for the LD_DEBUG variable. */
+#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS)
+static const char *_dl_reltypes_tab[] = {
+	[0]		"R_CRIS_NONE", "R_CRIS_8", "R_CRIS_16", "R_CRIS_32",
+	[4]		"R_CRIS_8_PCREL", "R_CRIS_16_PCREL", "R_CRIS_32_PCREL", "R_CRIS_GNU_VTINHERIT",
+	[8]		"R_CRIS_GNU_VTENTRY", "R_CRIS_COPY", "R_CRIS_GLOB_DAT", "R_CRIS_JUMP_SLOT",
+	[16]	"R_CRIS_RELATIVE", "R_CRIS_16_GOT", "R_CRIS_32_GOT", "R_CRIS_16_GOTPLT",
+	[32]	"R_CRIS_32_GOTPLT", "R_CRIS_32_GOTREL", "R_CRIS_32_PLT_GOTREL", "R_CRIS_32_PLT_PCREL",
+};
+
+static const char *
+_dl_reltypes(int type)
+{ 
+	static char buf[22];
+	const char *str;
+  
+	if (type >= (sizeof(_dl_reltypes_tab) / sizeof(_dl_reltypes_tab[0])) ||
+		NULL == (str = _dl_reltypes_tab[type])) { 
+    		str = _dl_simple_ltoa(buf, (unsigned long)(type));
+	}
+
+	return str;
+}
+
+static void 
+debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
+{ 
+	if (_dl_debug_symbols) { 
+		if (symtab_index) {
+			_dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
+				strtab + symtab[symtab_index].st_name,
+				symtab[symtab_index].st_value,
+				symtab[symtab_index].st_size,
+				symtab[symtab_index].st_info,
+				symtab[symtab_index].st_other,
+				symtab[symtab_index].st_shndx);
+    	}
+  	}
+} 
+    
+static void
+debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
+{   
+	if (_dl_debug_reloc) { 
+		int symtab_index;
+		const char *sym;
+
+		symtab_index = ELF32_R_SYM(rpnt->r_info);
+		sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
+        
+#ifdef ELF_USES_RELOCA
+		_dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x %s",
+			_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), rpnt->r_offset, rpnt->r_addend, sym);
+#else
+		_dl_dprintf(_dl_debug_file, "\n%s\toffset=%x %s", _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
+			rpnt->r_offset, sym);
+#endif
+	}
+}
+#endif
+
+/* Defined in resolve.S */
+extern int _dl_linux_resolve(void);
+
+unsigned long
+_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_offset)
+{
+  
+	int reloc_type;
+	int symtab_index;
+	char *strtab;
+	char *new_addr;
+	char **got_addr;
+	ELF_RELOC *reloc;
+	Elf32_Sym *symtab;
+	Elf32_Addr instr_addr;
+	
+	reloc = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr) + (reloc_offset >> 3);
+
+	reloc_type = ELF32_R_TYPE(reloc->r_info);
+	symtab_index = ELF32_R_SYM(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_CRIS_JUMP_SLOT) {
+		_dl_dprintf(_dl_debug_file, "%s: Incorrect relocation type for jump relocations.\n", _dl_progname);
+		_dl_exit(1);
+	}
+
+	/* Fetch the address of the jump instruction to fix up. */
+	instr_addr = ((Elf32_Addr) reloc->r_offset + (Elf32_Addr) tpnt->loadaddr);
+	got_addr = (char **) instr_addr;
+
+#ifdef DL_DEBUG_SYMBOLS
+	_dl_dprintf(_dl_debug_file, "Resolving symbol: %s\n", strtab + symtab[symtab_index].st_name);
+#endif
+
+	/* Fetch the address of the GOT entry. */
+	new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, tpnt->symbol_scope, tpnt, 0);
+	
+	if (!new_addr) {
+		_dl_dprintf(_dl_debug_file, "%s: Can't resolv symbol '%s'\n", _dl_progname, strtab + symtab[symtab_index].st_name);
+		_dl_exit(1);
+	}
+
+#if defined (SUPPORT_LD_DEBUG)
+	if (_dl_debug_bindings) {
+		_dl_dprintf(_dl_debug_file, "\nresolve function: %s", strtab + symtab[symtab_index].st_name);
+		
+		if (_dl_debug_detail)
+			_dl_dprintf(_dl_debug_file, "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
+	}
+#endif
+
+	*got_addr = new_addr;
+	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;
+	int reloc_type;
+	int symtab_index;
+	char *strtab;
+	Elf32_Sym *symtab;
+	ELF_RELOC *rpnt;
+	Elf32_Addr *reloc_addr;
+
+	/* Parse relocation information. */
+	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(ELF_RELOC);
+	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 = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) rpnt->r_offset);
+		reloc_type = ELF32_R_TYPE(rpnt->r_info);
+		symtab_index = ELF32_R_SYM(rpnt->r_info);
+
+		/*
+		 * Make sure we don't resolv the same symbols as we did
+		 * when ld.so bootstrapped itself.
+		 */
+		if (!symtab_index && tpnt->libtype == program_interpreter)
+		 	continue;
+		if (symtab_index && tpnt->libtype == program_interpreter &&
+			_dl_symbol(strtab + symtab[symtab_index].st_name))
+			continue;
+
+#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS)
+	{
+		unsigned long old_val = *reloc_addr;
+
+#endif
+
+		switch (reloc_type) {
+			case R_CRIS_NONE:
+				break;
+			case R_CRIS_JUMP_SLOT:
+				*reloc_addr += (Elf32_Addr) tpnt->loadaddr;
+				break;
+			default:
+				_dl_dprintf(_dl_debug_file, "%s: Can't handle relocation type (lazy).\n",
+					_dl_progname);
+#ifdef SUPPORT_LD_DEBUG
+					_dl_dprintf(_dl_debug_file, "%s ", _dl_reltypes(reloc_type));
+#endif
+				if (symtab_index)
+					_dl_dprintf(_dl_debug_file, "'%s'\n", strtab + symtab[symtab_index].st_name);
+
+				_dl_exit(1);
+		}
+#if defined(SUPPORT_LD_DEBUG)
+		if (_dl_debug_reloc && _dl_debug_detail)
+			_dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+	}
+#endif
+	}
+}
+
+int
+_dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, unsigned long rel_size, int type)
+{
+	int i;
+	int goof;
+	int reloc_type;
+	int symtab_index;
+	char *strtab;
+	Elf32_Sym *symtab;
+	ELF_RELOC *rpnt;
+	Elf32_Addr *reloc_addr;
+	Elf32_Addr symbol_addr;
+
+	goof = 0;
+	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(ELF_RELOC);
+
+	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 = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) 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;
+
+			if (symtab[symtab_index].st_shndx != SHN_UNDEF && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
+				symbol_addr = (Elf32_Addr) tpnt->loadaddr;
+			else
+				symbol_addr = (Elf32_Addr) _dl_find_hash(strtab + symtab[symtab_index].st_name,
+					tpnt->symbol_scope, (reloc_type == R_CRIS_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_dprintf(_dl_debug_file, "%s: Can't resolve '%s'\n",
+					_dl_progname, strtab + symtab[symtab_index].st_name);
+				goof++;
+			}
+			
+			symbol_addr += rpnt->r_addend;
+		}
+
+#if defined(SUPPORT_LD_DEBUG)
+	{
+		unsigned long old_val = *reloc_addr;
+		debug_sym(symtab,strtab,symtab_index);
+		debug_reloc(symtab,strtab,rpnt);
+#endif
+		
+		switch (reloc_type) {
+			case R_CRIS_GLOB_DAT:
+			case R_CRIS_JUMP_SLOT:
+			case R_CRIS_32:
+				*reloc_addr = symbol_addr;
+				break;
+			case R_CRIS_RELATIVE:
+				*reloc_addr = (Elf32_Addr) tpnt->loadaddr + rpnt->r_addend;
+				break;
+			case R_CRIS_COPY:
+				*reloc_addr = symbol_addr;
+				break;
+			case R_CRIS_8:
+				*(char *) reloc_addr = symbol_addr;
+				break;
+			case R_CRIS_16:
+				*(short *) reloc_addr = symbol_addr;
+				break;
+			case R_CRIS_8_PCREL:
+				*(char *) reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 1;
+				break;
+			case R_CRIS_16_PCREL:
+				*(short *) reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 2;
+				break;
+			case R_CRIS_32_PCREL:
+				*reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 4;
+				break;
+			case R_CRIS_NONE:
+				break;
+			default:
+				_dl_dprintf(_dl_debug_file, "%s: Can't handle relocation type ", _dl_progname);
+#ifdef SUPPORT_LD_DEBUG
+				_dl_dprintf(_dl_debug_file, "%s\n", _dl_reltypes(reloc_type));
+#endif
+				if (symtab_index) {
+					_dl_dprintf(_dl_debug_file, "'%s'\n", strtab + symtab[symtab_index].st_name);
+					return -1;
+				}
+		}
+#if defined(SUPPORT_LD_DEBUG)
+		if (_dl_debug_reloc && _dl_debug_detail)
+			_dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
+	}
+#endif
+	}
+	return goof;
+}
+
+/*
+ * This is done as a seperate step, because there are cases where
+ * information is first copied and later initialized. This results
+ * in the wrong information being copied.
+ */
+int
+_dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, unsigned long rel_size, int type)
+{
+	int i;
+	int reloc_type;
+	int goof;
+	int symtab_index;
+	char *strtab;
+	struct elf_resolve *tpnt;
+	Elf32_Sym *symtab;
+	ELF_RELOC *rpnt;
+	Elf32_Addr *reloc_addr;
+	Elf32_Addr symbol_addr;
+
+	goof = 0;
+	tpnt = xpnt->dyn;
+
+	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr);
+	rel_size = rel_size / sizeof(ELF_RELOC);
+
+	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 = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) rpnt->r_offset);
+		reloc_type = ELF32_R_TYPE(rpnt->r_info);
+
+		if (reloc_type != R_CRIS_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 = (Elf32_Addr) _dl_find_hash(strtab + 
+				symtab[symtab_index].st_name, xpnt->next, NULL, 1);
+
+			if (!symbol_addr) {
+				_dl_dprintf(_dl_debug_file, "%s: Can't resolv symbol '%s'\n",
+					_dl_progname, strtab + symtab[symtab_index].st_name);
+				goof++;
+			}
+		}
+
+		if (!goof) {
+#if defined(SUPPORT_LD_DEBUG)
+			if (_dl_debug_move)
+				_dl_dprintf(_dl_debug_file, "\n%s move %x bytes from %x to %x",
+					strtab + symtab[symtab_index].st_name,
+					symtab[symtab_index].st_size,
+					symbol_addr, symtab[symtab_index].st_value);
+#endif
+			_dl_memcpy((char *) symtab[symtab_index].st_value, (char *) symbol_addr,
+				symtab[symtab_index].st_size);
+		}
+	}
+
+	return goof;
+}

+ 137 - 0
ldso/ldso/cris/ld_syscalls.h

@@ -0,0 +1,137 @@
+/*
+ * This file contains the system call macros and syscall
+ * numbers used by the shared library loader. Taken from
+ * Linux/CRIS 2.4.17 version kernel.
+ */
+
+#define __NR_exit                 1
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_getpid              20
+#define __NR_getuid              24
+#define __NR_getgid              47
+#define __NR_geteuid             49
+#define __NR_getegid             50
+#define __NR_readlink            85
+#define __NR_mmap                90
+#define __NR_munmap              91
+#define __NR_stat               106
+#define __NR_mprotect           125
+
+/* 
+ * Here are the macros which define how this platform makes
+ * system calls.  This particular variant does _not_ set 
+ * errno since these will get called before the errno symbol 
+ * is dynamicly linked. 
+ */
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+  register long __a __asm__ ("r10"); \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1,type2 arg2) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+} 
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+          type5,arg5) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("move %6,$mof\n\t" \
+                        "movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d), "g" (arg5) \
+                        : "r10", "r9"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+          type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+  register long __a __asm__ ("r10") = (long) arg1; \
+  register long __b __asm__ ("r11") = (long) arg2; \
+  register long __c __asm__ ("r12") = (long) arg3; \
+  register long __d __asm__ ("r13") = (long) arg4; \
+  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
+                        "movu.w %1,$r9\n\tbreak 13" \
+                        : "=r" (__a) \
+                        : "g" (__NR_##name), "0" (__a), "r" (__b), \
+                          "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
+                        : "r10", "r9", "srp"); \
+  if(__a >= 0) \
+  	return (type) __a; \
+  return (type) -1; \
+}

+ 111 - 0
ldso/ldso/cris/ld_sysdep.h

@@ -0,0 +1,111 @@
+/* CRIS can never use Elf32_Rel relocations. */
+#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 long *) ARGS)
+
+/*
+ * Initialization sequence for a GOT.
+ */
+#define INIT_GOT(GOT_BASE,MODULE) 				\
+{                               				\
+	 GOT_BASE[1] = (unsigned long) MODULE; 			\
+	 GOT_BASE[2] = (unsigned long) _dl_linux_resolve; 	\
+} 
+
+/*
+ * 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_CRIS_GLOB_DAT:						\
+		case R_CRIS_JUMP_SLOT:						\
+		case R_CRIS_32:							\
+			*REL = SYMBOL;						\
+			break;							\
+		case R_CRIS_16_PCREL:						\
+			*(short *) *REL = SYMBOL + (RELP)->r_addend - *REL - 2;	\
+			break;							\
+		case R_CRIS_32_PCREL:						\
+			*REL = SYMBOL + (RELP)->r_addend - *REL - 4;		\
+			break;							\
+		case R_CRIS_NONE:						\
+			break;							\
+		case R_CRIS_RELATIVE:						\
+			*REL = (unsigned long) LOAD + (RELP)->r_addend;		\
+			break;							\
+		default:							\
+			_dl_exit(1);						\
+			break;							\
+	} 
+
+/*
+ * Transfer control to the user's application once the dynamic loader
+ * is done. This routine has to exit the current function, then call
+ * _dl_elf_main.
+ */
+#define START() __asm__ volatile ("moveq 0,$r8\n\t
+								   move $r8,$srp\n\t
+								   move.d %1,$sp\n\t
+								   jump %0\n\t" : : "r" (_dl_elf_main), "r" (args))
+
+/* Defined some magic numbers that this ld.so should accept. */
+#define MAGIC1 EM_CRIS
+#undef MAGIC2
+#define ELF_TARGET "CRIS"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry);
+
+/* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
+static inline unsigned long 
+cris_mod(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 = cris_mod(n, base);
+
+/* 8192 bytes alignment */
+#define PAGE_ALIGN 0xffffe000
+#define ADDR_ALIGN 0x1fff
+#define OFFS_ALIGN 0xffffe000

+ 48 - 0
ldso/ldso/cris/resolve.S

@@ -0,0 +1,48 @@
+/*
+ * This function is _not_ called directly.  It is jumped to from PLT 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.  When we get called 
+ * the stack contains reloc_offset and tpnt is in MOF.
+ *
+ * We save all the registers, setup R10 and R11 with the right arguments 
+ * then call _dl_linux_resolver(tpnt, reloc_offset). _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.
+ */		  
+
+.globl _dl_linux_resolve
+.type _dl_linux_resolve,@function
+
+_dl_linux_resolve:
+	push $r13
+	push $r12
+	push $r11
+	push $r10
+	push $r9
+	push $srp
+	move.d [$sp+6*4],$r11
+	move $mof,$r10
+#ifdef __PIC__
+	move.d $pc,$r0
+	sub.d .:GOTOFF,$r0
+	move.d _dl_linux_resolver:PLTG,$r9
+	add.d $r0,$r9
+	jsr $r9
+#else
+	jsr _dl_linux_resolver
+#endif
+	move.d $r10,[$sp+6*4]
+	pop $srp
+	pop $r9
+	pop $r10
+	pop $r11
+	pop $r12
+	pop $r13
+	jump [$sp+]
+
+	.size _dl_linux_resolve, . - _dl_linux_resolve