From 27ef34961183c110abc8c5fee05f1c5016c8042a Mon Sep 17 00:00:00 2001 From: Tobias Anderberg Date: Mon, 16 Sep 2002 08:11:43 +0000 Subject: Initial version of the dynamic linker code for the CRIS port. --- ldso/ldso/cris/boot1_arch.h | 17 ++ ldso/ldso/cris/dl-startup.h | 17 ++ ldso/ldso/cris/dl-syscalls.h | 137 +++++++++++++++ ldso/ldso/cris/dl-sysdep.h | 111 ++++++++++++ ldso/ldso/cris/elfinterp.c | 401 +++++++++++++++++++++++++++++++++++++++++++ ldso/ldso/cris/ld_syscalls.h | 137 +++++++++++++++ ldso/ldso/cris/ld_sysdep.h | 111 ++++++++++++ ldso/ldso/cris/resolve.S | 48 ++++++ 8 files changed, 979 insertions(+) create mode 100644 ldso/ldso/cris/boot1_arch.h create mode 100644 ldso/ldso/cris/dl-startup.h create mode 100644 ldso/ldso/cris/dl-syscalls.h create mode 100644 ldso/ldso/cris/dl-sysdep.h create mode 100644 ldso/ldso/cris/elfinterp.c create mode 100644 ldso/ldso/cris/ld_syscalls.h create mode 100644 ldso/ldso/cris/ld_sysdep.h create mode 100644 ldso/ldso/cris/resolve.S (limited to 'ldso') 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, + * + * 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 -- cgit v1.2.3