diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-08-08 14:35:49 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-08-08 14:35:49 +0000 |
commit | 9cba52f0aedbb95671e8a14e3fd5ff98381ff2b0 (patch) | |
tree | dd82b29998103d7d8ba34351e6fc3a12dc0ed7ac /ldso/ldso/sh | |
parent | 4c69b9f793fc1eae9190d8ba26dba25db616272f (diff) |
Patch from Stefan Allius and Edie C. Dost to add SuperH
shared library support. This also adds some cleaner error
handling, which I (Erik) then ported over to x86 and arm.
In addition Stefan added the following fixes:
- in hash.c was the lvalue handling of global library functions wrong.
To fix this I had to change the prototype of _dl_find_hash. (==> TIS and
ELF spec. Vers. 1.2)
- in ldso.c was the order of the .init sections calls wrong. Before we call
the initialization code of a library we have to check that all dependend
libraries are already initialized. This can easily made by calling it in the
revers loading order. For this I added a previous pointer chain.
- in ldso.c the ELF magics wasn't checked fo PPC, MIPS and SH architecture
Diffstat (limited to 'ldso/ldso/sh')
-rw-r--r-- | ldso/ldso/sh/boot1_arch.h | 23 | ||||
-rw-r--r-- | ldso/ldso/sh/dl-startup.h | 23 | ||||
-rw-r--r-- | ldso/ldso/sh/dl-syscalls.h | 7 | ||||
-rw-r--r-- | ldso/ldso/sh/dl-sysdep.h | 145 | ||||
-rw-r--r-- | ldso/ldso/sh/elfinterp.c | 416 | ||||
-rw-r--r-- | ldso/ldso/sh/ld_syscalls.h | 7 | ||||
-rw-r--r-- | ldso/ldso/sh/ld_sysdep.h | 145 | ||||
-rw-r--r-- | ldso/ldso/sh/resolve.S | 69 |
8 files changed, 835 insertions, 0 deletions
diff --git a/ldso/ldso/sh/boot1_arch.h b/ldso/ldso/sh/boot1_arch.h new file mode 100644 index 000000000..798121dc0 --- /dev/null +++ b/ldso/ldso/sh/boot1_arch.h @@ -0,0 +1,23 @@ +/* Any assmbly language/system dependent hacks needed to setup boot1.c so it + * will work as expected and cope with whatever platform specific wierdness is + * needed for this architecture. */ + +asm("\ + .text + .globl _dl_boot +_dl_boot: + mov r15, r4 + mov.l .L_dl_boot2, r1 + mova .L_dl_boot2, r0 + add r1, r0 + jsr @r0 + add #4, r4 + jmp @r0 + mov #0, r4 /* call _start with arg == 0 */ +.L_dl_boot2:\n\ + .long _dl_boot2-.\n\ + .previous\n\ +"); + +#define _dl_boot _dl_boot2 +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/sh/dl-startup.h b/ldso/ldso/sh/dl-startup.h new file mode 100644 index 000000000..798121dc0 --- /dev/null +++ b/ldso/ldso/sh/dl-startup.h @@ -0,0 +1,23 @@ +/* Any assmbly language/system dependent hacks needed to setup boot1.c so it + * will work as expected and cope with whatever platform specific wierdness is + * needed for this architecture. */ + +asm("\ + .text + .globl _dl_boot +_dl_boot: + mov r15, r4 + mov.l .L_dl_boot2, r1 + mova .L_dl_boot2, r0 + add r1, r0 + jsr @r0 + add #4, r4 + jmp @r0 + mov #0, r4 /* call _start with arg == 0 */ +.L_dl_boot2:\n\ + .long _dl_boot2-.\n\ + .previous\n\ +"); + +#define _dl_boot _dl_boot2 +#define LD_BOOT(X) static void * __attribute__ ((unused)) _dl_boot (X) diff --git a/ldso/ldso/sh/dl-syscalls.h b/ldso/ldso/sh/dl-syscalls.h new file mode 100644 index 000000000..793dc9110 --- /dev/null +++ b/ldso/ldso/sh/dl-syscalls.h @@ -0,0 +1,7 @@ +/* Define the __set_errno macro as nothing so that we don't bother + * setting errno, which is important since we make system calls + * before the errno symbol is dynamicly linked. */ + +#define __set_errno(X) +#include "sys/syscall.h" + diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h new file mode 100644 index 000000000..dc1b895b9 --- /dev/null +++ b/ldso/ldso/sh/dl-sysdep.h @@ -0,0 +1,145 @@ +/* + * Various assmbly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + */ + +/* + * Define this if the system uses RELOCA. + */ +#define ELF_USES_RELOCA + +/* + * Get a pointer to the argv array. On many platforms this can be just + * the address if the first argument, on other platforms we need to + * do something a little more subtle here. + */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) + +/* + * Initialization sequence for a GOT. + */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) (MODULE); \ +} + +/* + * Here is a macro to perform a relocation. This is only used when + * bootstrapping the dynamic loader. RELP is the relocation that we + * are performing, REL is the pointer to the address we are relocating. + * SYMBOL is the symbol involved in the relocation, and LOAD is the + * load address. + */ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)){ \ + case R_SH_REL32: \ + *(REL) += (RELP)->r_addend - (LOAD); \ + break; \ + case R_SH_DIR32: \ + *(REL) += (SYMBOL) + (RELP)->r_addend; \ + break; \ + case R_SH_RELATIVE: \ + *(REL) += (LOAD); \ + break; \ + case R_SH_NONE: \ + break; \ + default: \ + SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type "); \ + SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1); \ + SEND_STDERR("REL, SYMBOL, LOAD: "); \ + SEND_ADDRESS_STDERR(REL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(SYMBOL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(LOAD, 1); \ + _dl_exit(1); \ + } + + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. This routine has to exit the current function, then + * call the _dl_elf_main function. + */ + +#define START() return _dl_elf_main; + + + +/* Here we define the magic numbers that this dynamic loader should accept */ + +#define MAGIC1 EM_SH +#undef MAGIC2 +/* Used for error messages */ +#define ELF_TARGET "sh" + +struct elf_resolve; +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +static __inline__ unsigned int +_dl_urem(unsigned int n, unsigned int base) +{ +register unsigned int __r0 __asm__ ("r0"); +register unsigned int __r4 __asm__ ("r4") = n; +register unsigned int __r5 __asm__ ("r5") = base; + + __asm__ (" + mov #0, r0 + div0u + + ! get one bit from the msb of the numerator into the T + ! bit and divide it by whats in %2. Put the answer bit + ! into the T bit so it can come out again at the bottom + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 + mov r4, r0 +" + : "=r" (__r0) + : "r" (__r4), "r" (__r5) + : "r4", "cc"); + + return n - (base * __r0); +} + +#define do_rem(result, n, base) ((result) = _dl_urem((n), (base))) + +/* 4096 bytes alignment */ +#define PAGE_ALIGN 0xfffff000 +#define ADDR_ALIGN 0xfff +#define OFFS_ALIGN 0x7ffff000 diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c new file mode 100644 index 000000000..2a0ab9f7a --- /dev/null +++ b/ldso/ldso/sh/elfinterp.c @@ -0,0 +1,416 @@ +/* vi: set sw=4 ts=4: */ +/* SuperH ELF shared library loader suppport + * + * Copyright (C) 2002, Stefan Allius <allius@atecom.com> and + * Eddie C. Dost <ecd@atecom.com> + * + * All rights reserved. + * + * 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. + */ + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_DEBUG_SYMBOLS) +static const char *_dl_reltypes_tab[] = +{ + [0] "R_SH_NONE", "R_SH_DIR32", "R_SH_REL32", "R_SH_DIR8WPN", + [4] "R_SH_IND12W", "R_SH_DIR8WPL", "R_SH_DIR8WPZ", "R_SH_DIR8BP", + [8] "R_SH_DIR8W", "R_SH_DIR8L", + [25] "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES", + [28] "R_SH_COUNT", "R_SH_ALIGN", "R_SH_CODE", "R_SH_DATA", + [32] "R_SH_LABEL", "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY", +[160] "R_SH_GOT32", "R_SH_PLT32", "R_SH_COPY", "R_SH_GLOB_DAT", +[164] "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF", "R_SH_GOTPC", +}; + +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 + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have + I ever taken any courses on internals. This program was developed using + information available through the book "UNIX SYSTEM V RELEASE 4, + Programmers guide: Ansi C and Programming Support Tools", which did + a more than adequate job of explaining everything required to get this + working. */ + +extern int _dl_linux_resolve(void); + +unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +{ + int reloc_type; + ELF_RELOC *this_reloc; + char *strtab; + Elf32_Sym *symtab; + int symtab_index; + char *rel_addr; + char *new_addr; + char **got_addr; + unsigned long instr_addr; + + rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); + + this_reloc = (ELF_RELOC *) (rel_addr + reloc_entry); + reloc_type = ELF32_R_TYPE(this_reloc->r_info); + symtab_index = ELF32_R_SYM(this_reloc->r_info); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + if (reloc_type != R_SH_JMP_SLOT) { + _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", + _dl_progname); + _dl_exit(1); + } + + /* Address of jump instruction to fix up */ + instr_addr = ((unsigned long) this_reloc->r_offset + + (unsigned long) tpnt->loadaddr); + got_addr = (char **) instr_addr; + + + /* Get the address of the GOT entry */ + new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, + tpnt->symbol_scope, tpnt, resolver); + if (!new_addr) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_exit(1); + } + +#if defined (SUPPORT_LD_DEBUG) || defined (LD_NEVER_FIXUP_SYMBOLS) + if ((unsigned long) got_addr < 0x20000000) + { +#ifndef 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 +#ifndef LD_NEVER_FIXUP_SYMBOLS + *got_addr = new_addr; +#endif + } else { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + + return (unsigned long) new_addr; +} + + +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) +{ + int i; + char *strtab; + int goof = 0; + Elf32_Sym *symtab; + ELF_RELOC *rpnt; + int symtab_index; + /* Now parse the 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++) { + int res; + + symtab_index = ELF32_R_SYM(rpnt->r_info); + + /* When the dynamic linker bootstrapped itself, it resolved some symbols. + Make sure we do not do them again */ + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + if (symtab_index && tpnt->libtype == program_interpreter && + _dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + +#if defined (SUPPORT_LD_DEBUG) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); +#endif + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (SUPPORT_LD_DEBUG) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol '%s'\n"); + goof += res; + } + } + return goof; +} + + +static int +_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + + symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, + scope, + (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL), symbolrel); + + /* + * 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) { + goof++; + } + } + + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_SH_NONE: + break; + case R_SH_COPY: + /* handled later on */ + break; + case R_SH_DIR32: + *reloc_addr += symbol_addr + rpnt->r_addend; + break; + case R_SH_JMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_SH_REL32: + *reloc_addr += rpnt->r_addend - + (unsigned long) tpnt->loadaddr; + break; + case R_SH_RELATIVE: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + default: + return -1; /*call _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 + + return goof; +} + + +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + unsigned long *reloc_addr; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (SUPPORT_LD_DEBUG) + { + unsigned long old_val = *reloc_addr; +#endif + switch (reloc_type) { + case R_SH_NONE: + break; + case R_SH_JMP_SLOT: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + default: + return -1; /*call _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 + return 0; + +} + +/* This is done as a separate step, because there are cases where + information is first copied and later initialized. This results in + the wrong information being copied. Someone at Sun was complaining about + a bug in the handling of _COPY by SVr4, and this may in fact be what he + was talking about. Sigh. */ + +/* No, there are cases where the SVr4 linker fails to emit COPY relocs + at all */ +static int +_dl_do_copy (struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int goof = 0; + + reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_type = ELF32_R_TYPE(rpnt->r_info); + if (reloc_type != R_SH_COPY) + return 0; + symtab_index = ELF32_R_SYM(rpnt->r_info); + symbol_addr = 0; + + if (symtab_index) { + + symbol_addr = (unsigned long) _dl_find_hash(strtab + + symtab[symtab_index].st_name, scope, + NULL, copyrel); + if (!symbol_addr) 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; +} + + +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + (void)_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} + +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} + +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) +{ + return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy); +} + + diff --git a/ldso/ldso/sh/ld_syscalls.h b/ldso/ldso/sh/ld_syscalls.h new file mode 100644 index 000000000..793dc9110 --- /dev/null +++ b/ldso/ldso/sh/ld_syscalls.h @@ -0,0 +1,7 @@ +/* Define the __set_errno macro as nothing so that we don't bother + * setting errno, which is important since we make system calls + * before the errno symbol is dynamicly linked. */ + +#define __set_errno(X) +#include "sys/syscall.h" + diff --git a/ldso/ldso/sh/ld_sysdep.h b/ldso/ldso/sh/ld_sysdep.h new file mode 100644 index 000000000..dc1b895b9 --- /dev/null +++ b/ldso/ldso/sh/ld_sysdep.h @@ -0,0 +1,145 @@ +/* + * Various assmbly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + */ + +/* + * Define this if the system uses RELOCA. + */ +#define ELF_USES_RELOCA + +/* + * Get a pointer to the argv array. On many platforms this can be just + * the address if the first argument, on other platforms we need to + * do something a little more subtle here. + */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) + +/* + * Initialization sequence for a GOT. + */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) (MODULE); \ +} + +/* + * Here is a macro to perform a relocation. This is only used when + * bootstrapping the dynamic loader. RELP is the relocation that we + * are performing, REL is the pointer to the address we are relocating. + * SYMBOL is the symbol involved in the relocation, and LOAD is the + * load address. + */ +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)){ \ + case R_SH_REL32: \ + *(REL) += (RELP)->r_addend - (LOAD); \ + break; \ + case R_SH_DIR32: \ + *(REL) += (SYMBOL) + (RELP)->r_addend; \ + break; \ + case R_SH_RELATIVE: \ + *(REL) += (LOAD); \ + break; \ + case R_SH_NONE: \ + break; \ + default: \ + SEND_STDERR("BOOTSTRAP_RELOC: unhandled reloc type "); \ + SEND_NUMBER_STDERR(ELF32_R_TYPE((RELP)->r_info), 1); \ + SEND_STDERR("REL, SYMBOL, LOAD: "); \ + SEND_ADDRESS_STDERR(REL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(SYMBOL, 0); \ + SEND_STDERR(", "); \ + SEND_ADDRESS_STDERR(LOAD, 1); \ + _dl_exit(1); \ + } + + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. This routine has to exit the current function, then + * call the _dl_elf_main function. + */ + +#define START() return _dl_elf_main; + + + +/* Here we define the magic numbers that this dynamic loader should accept */ + +#define MAGIC1 EM_SH +#undef MAGIC2 +/* Used for error messages */ +#define ELF_TARGET "sh" + +struct elf_resolve; +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +static __inline__ unsigned int +_dl_urem(unsigned int n, unsigned int base) +{ +register unsigned int __r0 __asm__ ("r0"); +register unsigned int __r4 __asm__ ("r4") = n; +register unsigned int __r5 __asm__ ("r5") = base; + + __asm__ (" + mov #0, r0 + div0u + + ! get one bit from the msb of the numerator into the T + ! bit and divide it by whats in %2. Put the answer bit + ! into the T bit so it can come out again at the bottom + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 ; div1 r5, r0 + rotcl r4 + mov r4, r0 +" + : "=r" (__r0) + : "r" (__r4), "r" (__r5) + : "r4", "cc"); + + return n - (base * __r0); +} + +#define do_rem(result, n, base) ((result) = _dl_urem((n), (base))) + +/* 4096 bytes alignment */ +#define PAGE_ALIGN 0xfffff000 +#define ADDR_ALIGN 0xfff +#define OFFS_ALIGN 0x7ffff000 diff --git a/ldso/ldso/sh/resolve.S b/ldso/ldso/sh/resolve.S new file mode 100644 index 000000000..4d8eee6c2 --- /dev/null +++ b/ldso/ldso/sh/resolve.S @@ -0,0 +1,69 @@ +/* + * Stolen from glibc-2.2.2 by Eddie C. Dost <ecd@atecom.com> + */ + + .text + .globl _dl_linux_resolve + .type _dl_linux_resolve, @function + .balign 16 +_dl_linux_resolve: + mov.l r3, @-r15 + mov.l r4, @-r15 + mov.l r5, @-r15 + mov.l r6, @-r15 + mov.l r7, @-r15 + mov.l r12, @-r15 + movt r3 ! Save T flag + mov.l r3, @-r15 + +#ifdef HAVE_FPU + sts.l fpscr, @-r15 + mov #8,r3 + swap.w r3, r3 + lds r3, fpscr + fmov.s fr11, @-r15 + fmov.s fr10, @-r15 + fmov.s fr9, @-r15 + fmov.s fr8, @-r15 + fmov.s fr7, @-r15 + fmov.s fr6, @-r15 + fmov.s fr5, @-r15 + fmov.s fr4, @-r15 +#endif + sts.l pr, @-r15 + + mov r2, r4 ! link map address + + mov.l 3f, r0 + jsr @r0 ! Call resolver + mov r1, r5 ! Reloc offset + + lds.l @r15+, pr ! Get register content back + +#ifdef HAVE_FPU + fmov.s @r15+, fr4 + fmov.s @r15+, fr5 + fmov.s @r15+, fr6 + fmov.s @r15+, fr7 + fmov.s @r15+, fr8 + fmov.s @r15+, fr9 + fmov.s @r15+, fr10 + fmov.s @r15+, fr11 + lds.l @r15+, fpscr +#endif + + mov.l @r15+, r3 + shal r3 ! Load T flag + mov.l @r15+, r12 + mov.l @r15+, r7 + mov.l @r15+, r6 + mov.l @r15+, r5 + mov.l @r15+, r4 + jmp @r0 ! Jump to function address + mov.l @r15+, r3 + + .balign 4 +3: + .long _dl_linux_resolver + .size _dl_linux_resolve, . - _dl_linux_resolve + |