summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorTobias Anderberg <tobias.anderberg@axis.com>2002-09-16 08:11:43 +0000
committerTobias Anderberg <tobias.anderberg@axis.com>2002-09-16 08:11:43 +0000
commit27ef34961183c110abc8c5fee05f1c5016c8042a (patch)
treedf720d9ff9ffd882ec21b96e71543692895cfa68 /ldso
parent66812a6f8c6cdc5fd2495ebf45ebaf606eb80198 (diff)
Initial version of the dynamic linker code for the CRIS port.
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/cris/boot1_arch.h17
-rw-r--r--ldso/ldso/cris/dl-startup.h17
-rw-r--r--ldso/ldso/cris/dl-syscalls.h137
-rw-r--r--ldso/ldso/cris/dl-sysdep.h111
-rw-r--r--ldso/ldso/cris/elfinterp.c401
-rw-r--r--ldso/ldso/cris/ld_syscalls.h137
-rw-r--r--ldso/ldso/cris/ld_sysdep.h111
-rw-r--r--ldso/ldso/cris/resolve.S48
8 files changed, 979 insertions, 0 deletions
diff --git a/ldso/ldso/cris/boot1_arch.h b/ldso/ldso/cris/boot1_arch.h
new file mode 100644
index 000000000..5fe5cae43
--- /dev/null
+++ b/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)
diff --git a/ldso/ldso/cris/dl-startup.h b/ldso/ldso/cris/dl-startup.h
new file mode 100644
index 000000000..5fe5cae43
--- /dev/null
+++ b/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)
diff --git a/ldso/ldso/cris/dl-syscalls.h b/ldso/ldso/cris/dl-syscalls.h
new file mode 100644
index 000000000..5e5fe6078
--- /dev/null
+++ b/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; \
+}
diff --git a/ldso/ldso/cris/dl-sysdep.h b/ldso/ldso/cris/dl-sysdep.h
new file mode 100644
index 000000000..e915bf600
--- /dev/null
+++ b/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
diff --git a/ldso/ldso/cris/elfinterp.c b/ldso/ldso/cris/elfinterp.c
new file mode 100644
index 000000000..9a0b42635
--- /dev/null
+++ b/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;
+}
diff --git a/ldso/ldso/cris/ld_syscalls.h b/ldso/ldso/cris/ld_syscalls.h
new file mode 100644
index 000000000..5e5fe6078
--- /dev/null
+++ b/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; \
+}
diff --git a/ldso/ldso/cris/ld_sysdep.h b/ldso/ldso/cris/ld_sysdep.h
new file mode 100644
index 000000000..e915bf600
--- /dev/null
+++ b/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
diff --git a/ldso/ldso/cris/resolve.S b/ldso/ldso/cris/resolve.S
new file mode 100644
index 000000000..406a3b269
--- /dev/null
+++ b/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