From ee92c0fe5c1b9d59508273916e2c9a75b68dbc13 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 21 Apr 2016 01:25:29 +0200 Subject: nds32: add support for new architecture Add support for Andes Technology NDS32 architecture. See here http://www.andestech.com/en/index/index.htm for more informaton. Verification of the port from an older uClibc port was done on a sponsored AG101p board. The testsuite only has 5 errors, three are related to an existing bug in dlclose() with LT.old, also happening on cris32 and m68k. Failures to fallocate/posix_fallocate are unresolved. Thanks to Andes Technology sponsoring the hardware and being very helpful while doing the uClibc-ng porting. Signed-off-by: Waldemar Brodkorb --- ldso/ldso/nds32/dl-debug.h | 25 ++++ ldso/ldso/nds32/dl-startup.h | 175 +++++++++++++++++++++++ ldso/ldso/nds32/dl-syscalls.h | 11 ++ ldso/ldso/nds32/dl-sysdep.h | 99 +++++++++++++ ldso/ldso/nds32/elfinterp.c | 315 ++++++++++++++++++++++++++++++++++++++++++ ldso/ldso/nds32/resolve.S | 76 ++++++++++ 6 files changed, 701 insertions(+) create mode 100644 ldso/ldso/nds32/dl-debug.h create mode 100644 ldso/ldso/nds32/dl-startup.h create mode 100644 ldso/ldso/nds32/dl-syscalls.h create mode 100644 ldso/ldso/nds32/dl-sysdep.h create mode 100644 ldso/ldso/nds32/elfinterp.c create mode 100644 ldso/ldso/nds32/resolve.S (limited to 'ldso') diff --git a/ldso/ldso/nds32/dl-debug.h b/ldso/ldso/nds32/dl-debug.h new file mode 100644 index 000000000..ef4c57d91 --- /dev/null +++ b/ldso/ldso/nds32/dl-debug.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +static const char *_dl_reltypes_tab[] = +{ + [0] "R_NDS32_NONE", "R_NDS32_16", "R_NDS32_32", "R_NDS32_20", + [4] "R_NDS32_9_PCREL", "R_NDS32_15_PCREL", "R_NDS32_17_PCREL", "R_NDS32_25_PCREL", + [8] "R_NDS32_HI20", "R_NDS32_LO12S3", "R_NDS32_LO12S2", "R_NDS32_LO12S1", + [12] "R_NDS32_LO12S0", "R_NDS32_SDA15S3", "R_NDS32_SDA15S2", "R_NDS32_SDA15S1", + [16] "R_NDS32_SDA15S0", "R_NDS32_GNU_VTINHERIT", "R_NDS32_GNU_VTENTRY", "R_NDS32_16_RELA", + [20] "R_NDS32_32_RELA" "R_NDS32_20_RELA", "R_NDS32_9_PCREL_RELA", "R_NDS32_15_PCREL_RELA", + [24] "R_NDS32_17_PCREL_RELA", "R_NDS32_25_PCREL_RELA", "R_NDS32_HI20_RELA", "R_NDS32_LO12S3_RELA", + [28] "R_NDS32_LO12S2_RELA", "R_NDS32_LO12S1_RELA", "R_NDS32_LO12S0_RELA", "R_NDS32_SDA15S3_RELA", + [32] "R_NDS32_SDA15S2_RELA", "R_NDS32_SDA15S1_RELA", "R_NDS32_SDA15S0_RELA", "R_NDS32_RELA_GNU_VTINHERIT", + [36] "R_NDS32_RELA_GNU_VTENTRY", "R_NDS32_GOT20", "R_NDS32_25_PLTREL", "R_NDS32_COPY", + [40] "R_NDS32_GLOB_DAT", "R_NDS32_JMP_SLOT", "R_NDS32_RELATIVE", "R_NDS32_GOTOFF", + [44] "R_NDS32_GOTPC20", "R_NDS32_GOT_HI20", "R_NDS32_GOT_LO12", "R_NDS32_GOTPC_HI20", + [48] "R_NDS32_GOTPC_LO12", "R_NDS32_GOTOFF_HI20", "R_NDS32_GOTOFF_LO12", "R_NDS32_INSN16", + [52] "R_NDS32_LABEL", "R_NDS32_LONGCALL1", "R_NDS32_LONGCALL2", "R_NDS32_LONGCALL3", + [56] "R_NDS32_LONGJUMP1", "R_NDS32_LONGJUMP2", "R_NDS32_LONGJUMP3", "R_NDS32_LOADSTORE", + [60] "R_NDS32_9_FIXED_RELA", "R_NDS32_15_FIXED_RELA", "R_NDS32_17_FIXED_RELA", "R_NDS32_25_FIXED_RELA", + [64] "R_NDS32_PLTREL_HI20", "R_NDS32_PLTREL_LO12", "R_NDS32_PLT_GOTREL_HI20", "R_NDS32_PLT_GOTREL_LO12", +}; diff --git a/ldso/ldso/nds32/dl-startup.h b/ldso/ldso/nds32/dl-startup.h new file mode 100644 index 000000000..f700531ca --- /dev/null +++ b/ldso/ldso/nds32/dl-startup.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Need bootstrap relocations */ +#define ARCH_NEEDS_BOOTSTRAP_RELOCS + +#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) +# define STACK_PUSH +# define STACK_POP +#else +# define STACK_PUSH "addi $sp, $sp, -24" +# define STACK_POP "addi $sp, $sp, 24" +#endif + + +#ifdef __NDS32_N1213_43U1H__ +__asm__("\ + .text\n\ + .globl _start\n\ + .globl _dl_start\n\ + .globl _dl_start_user\n\ + .type _start,#function\n\ + .type _dl_start,#function\n\ + .type _dl_start_user,#function\n\ + .align 4\n\ + .pic\n\ +1:\n\ + ret\n\ +_start:\n\ + ! we are PIC code, so get global offset table\n\ + jal 1b\n\ + sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_)\n\ + ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+4)\n\ + add $gp, $lp, $gp\n\ +\n\ + ! at start time, all the args are on the stack\n\ + addi $r0, $sp, 0\n\ + ! adjust stack\n\ + !addi $sp, $sp, -24\n\ + "STACK_PUSH"\n\ + bal _dl_start@PLT\n\ + ! save user entry point in r6\n\ + addi $r6, $r0, 0\n\ + ! adjust sp and reload registers\n\ + !addi $sp, $sp, 24\n\ + "STACK_POP"\n\ +\n\ +_dl_start_user:\n\ +\n\ + ! See if we were run as a command with the executable file\n\ + ! name as an extra leading argument.\n\ + ! skip these arguments\n\ + l.w $r2, _dl_skip_args@GOTOFF ! args to skip\n\ + lwi $r0, [$sp+0] ! original argc\n\ + slli $r1, $r2, 2 ! offset for new sp\n\ + add $sp, $sp, $r1 ! adjust sp to skip args\n\ + sub $r0, $r0, $r2 ! set new argc\n\ + swi $r0, [$sp+0] ! save new argc\n\ +\n\ + ! load address of _dl_fini finalizer function\n\ + la $r5, _dl_fini@GOTOFF\n\ + ! jump to the user_s entry point\n\ + addi $r15, $r6, 0\n\ + jr $r15\n\ + .size _dl_start_user, . - _dl_start_user\n\ + .previous\n\ +"); +#else +__asm__("\ + .text\n\ + .globl _start\n\ + .globl _dl_start\n\ + .globl _dl_start_user\n\ + .type _start,#function\n\ + .type _dl_start,#function\n\ + .type _dl_start_user,#function\n\ + .align 4\n\ + .pic\n\ +_start:\n\ + ! we are PIC code, so get global offset table\n\ + mfusr $r15, $PC \n\ + sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_ + 4)\n\ + ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 8)\n\ + add $gp, $r15, $gp\n\ +\n\ + ! at start time, all the args are on the stack\n\ + addi $r0, $sp, 0\n\ + ! adjust stack\n\ + !addi $sp, $sp, -24\n\ + "STACK_PUSH"\n\ + bal _dl_start@PLT\n\ + ! save user entry point in r6\n\ + addi $r6, $r0, 0\n\ + ! adjust sp and reload registers\n\ + !addi $sp, $sp, 24\n\ + "STACK_POP"\n\ +\n\ +_dl_start_user:\n\ + ! See if we were run as a command with the executable file\n\ + ! name as an extra leading argument.\n\ + ! skip these arguments\n\ + l.w $r2, _dl_skip_args@GOTOFF ! args to skip\n\ + lwi $r0, [$sp+0] ! original argc\n\ + slli $r1, $r2, 2 ! offset for new sp\n\ + add $sp, $sp, $r1 ! adjust sp to skip args\n\ + sub $r0, $r0, $r2 ! set new argc\n\ + swi $r0, [$sp+0] ! save new argc\n\ +\n\ + ! load address of _dl_fini finalizer function\n\ + la $r5, _dl_fini@GOTOFF\n\ + ! jump to the user_s entry point\n\ + jr $r6\n\ + .size _dl_start_user, . - _dl_start_user\n\ + .previous\n\ +"); +#endif + +#define COPY_UNALIGNED_WORD(swp, twp, align) \ + { \ + void *__s = (swp), *__t = (twp); \ + unsigned char *__s1 = __s, *__t1 = __t; \ + unsigned short *__s2 = __s, *__t2 = __t; \ + unsigned long *__s4 = __s, *__t4 = __t; \ + switch ((align)) \ + { \ + case 0: \ + *__t4 = *__s4; \ + break; \ + case 2: \ + *__t2++ = *__s2++; \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ + } + +/* 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)+1) + +/* Handle relocation of the symbols in the dynamic loader. */ +static __always_inline +void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr, + unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab) +{ + Elf32_Addr value; + switch (ELF32_R_TYPE(rpnt->r_info)) { + case R_NDS32_NONE: + break; + case R_NDS32_32: + case R_NDS32_GLOB_DAT: + case R_NDS32_JMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_NDS32_32_RELA: + value = symbol_addr + rpnt->r_addend; + COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3); + break; +#undef COPY_UNALIGNED_WORD + case R_NDS32_RELATIVE: + *reloc_addr = load_addr + rpnt->r_addend; + break; + default: + SEND_STDERR("Unsupported relocation type\n"); + _dl_exit(1); + } +} diff --git a/ldso/ldso/nds32/dl-syscalls.h b/ldso/ldso/nds32/dl-syscalls.h new file mode 100644 index 000000000..54b8839d8 --- /dev/null +++ b/ldso/ldso/nds32/dl-syscalls.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* We can't use the real errno in ldso, since it has not yet + * been dynamicly linked in yet. */ +#include "sys/syscall.h" +extern int _dl_errno; +#undef __set_errno +#define __set_errno(X) {(_dl_errno) = (X);} diff --git a/ldso/ldso/nds32/dl-sysdep.h b/ldso/ldso/nds32/dl-sysdep.h new file mode 100644 index 000000000..c4a32ca71 --- /dev/null +++ b/ldso/ldso/nds32/dl-sysdep.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Define this if the system uses RELOCA. */ +#define ELF_USES_RELOCA +#include +/* Initialization sequence for the GOT. */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) MODULE; \ +} + +static __inline__ unsigned long nds32_modulus(unsigned long m, unsigned long p) +{ + unsigned long i,t,inc; + i=p; t=0; + while (!(i&(1<<31))) { + i<<=1; + t++; + } + t--; + for (inc=t;inc>2;inc--) { + i=p<=i) { + m-=i; + i<<=1; + if (i&(1<<31)) + break; + if (i=p) { + m-=p; + } + return m; +} +#define do_rem(result, n, base) ((result) = nds32_modulus(n, base)) + +/* Here we define the magic numbers that this dynamic loader should accept */ +#define MAGIC1 EM_NDS32 +#undef MAGIC2 + +/* Used for error messages */ +#define ELF_TARGET "NDS32" + +struct elf_resolve; +unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so + PLT entries should not be allowed to define the value. + ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one + of the main executable's symbols, as for a COPY reloc. */ +#define elf_machine_type_class(type) \ + ((((type) == R_NDS32_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_NDS32_COPY) * ELF_RTYPE_CLASS_COPY)) + +/* Return the link-time address of _DYNAMIC. Conveniently, this is the + first element of the GOT. We used to use the PIC register to do this + without a constant pool reference, but GCC 4.2 will use a pseudo-register + for the PIC base, so it may not be in r10. */ +static __inline__ Elf32_Addr __attribute__ ((unused)) +elf_machine_dynamic (void) +{ + Elf32_Addr link_addr; + __asm__ ( "l.w %0, _GLOBAL_OFFSET_TABLE_@GOTOFF": "=r" (link_addr) ); + return link_addr; +} + +/* Return the run-time load address of the shared object. */ +static __inline__ Elf32_Addr __attribute__ ((unused)) +elf_machine_load_address (void) +{ + /* It doesn't matter what variable this is, the reference never makes + it to assembly. We need a dummy reference to some global variable + via the GOT to make sure the compiler initialized %ebx in time. */ + + Elf32_Addr addr; + __asm__ ("la %0, _dl_start@GOTOFF\n" : "=r" (addr) ); + return addr - elf_machine_dynamic(); +} + +static __inline__ void +elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, + Elf32_Word relative_count) +{ + Elf32_Rela * rpnt = (void *) rel_addr; + --rpnt; + do { + Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset); + + *reloc_addr = load_off + rpnt->r_addend; + } while (--relative_count); +} diff --git a/ldso/ldso/nds32/elfinterp.c b/ldso/ldso/nds32/elfinterp.c new file mode 100644 index 000000000..bf5c901d1 --- /dev/null +++ b/ldso/ldso/nds32/elfinterp.c @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* NDS32 ELF shared library loader suppport + * + * Copyright (C) 2001-2004 Erik Andersen + * + * 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. + */ + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have + I ever taken any courses on internals. This program was developed using + information available through the book "UNIX SYSTEM V RELEASE 4, + Programmers guide: Ansi C and Programming Support Tools", which did + a more than adequate job of explaining everything required to get this + working. */ + +#include "ldso.h" + +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; + char *symname; + Elf32_Sym *symtab; + ELF_RELOC *rel_addr; + int symtab_index; + char *new_addr; + char **got_addr; + unsigned long instr_addr; + + rel_addr = (ELF_RELOC *) tpnt->dynamic_info[DT_JMPREL]; + + this_reloc = rel_addr + reloc_entry/sizeof(ELF_RELOC); + 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]; + strtab = (char *) tpnt->dynamic_info[DT_STRTAB]; + symname = strtab + symtab[symtab_index].st_name; + + if (unlikely(reloc_type != R_NDS32_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(symname, &_dl_loaded_modules->symbol_scope, tpnt, + ELF_RTYPE_CLASS_PLT, NULL); + if (unlikely(!new_addr)) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, symname); + _dl_exit(1); + } +#if defined (__SUPPORT_LD_DEBUG__) + if ((unsigned long) got_addr < 0x40000000) + { + if (_dl_debug_bindings) + { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); + if (_dl_debug_detail) _dl_dprintf(_dl_debug_file, + "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } + } + if (!_dl_debug_nofixups) { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + + return (unsigned long) new_addr; +} + +static int +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) +{ + int symtab_index; + int i; + char *strtab; + int goof = 0; + ElfW(Sym) *symtab; + ELF_RELOC *rpnt; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) rel_addr; + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *) tpnt->dynamic_info[DT_STRTAB]; + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF32_R_SYM(rpnt->r_info); + + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); + + 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 (unlikely(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); + } + if (unlikely(res >0)) + { + _dl_dprintf(2, "can't resolve symbol\n"); + goof += res; + } + } + return goof; +} + + +static int +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname = NULL; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int goof = 0; + struct symbol_ref sym_ref; + + 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; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + + if (symtab_index) { + symname = strtab + symtab[symtab_index].st_name; + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + /* + * 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_WEAK) { + _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", + _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_exit (1); + } + } + +#define COPY_UNALIGNED_WORD(swp, twp, align) \ + { \ + void *__s = (swp), *__t = (twp); \ + unsigned char *__s1 = __s, *__t1 = __t; \ + unsigned short *__s2 = __s, *__t2 = __t; \ + unsigned long *__s4 = __s, *__t4 = __t; \ + switch ((align)) \ + { \ + case 0: \ + *__t4 = *__s4; \ + break; \ + case 2: \ + *__t2++ = *__s2++; \ + *__t2 = *__s2; \ + break; \ + default: \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1++ = *__s1++; \ + *__t1 = *__s1; \ + break; \ + } \ + } + +#if defined (__SUPPORT_LD_DEBUG__) + { + unsigned long old_val = *reloc_addr; +#endif + symbol_addr += rpnt->r_addend ; + switch (reloc_type) { + case R_NDS32_NONE: + break; + case R_NDS32_32: + case R_NDS32_GLOB_DAT: + case R_NDS32_JMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_NDS32_32_RELA: + COPY_UNALIGNED_WORD (&symbol_addr, reloc_addr,(int) reloc_addr & 3); + break; +#undef COPY_UNALIGNED_WORD + case R_NDS32_RELATIVE: + *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend; + break; + case R_NDS32_COPY: + _dl_memcpy((void *) reloc_addr, + (void *) symbol_addr, symtab[symtab_index].st_size); + 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 r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(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_NDS32_NONE: + break; + case R_NDS32_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; + +} + +void +_dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, + unsigned long rel_size) +{ + _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} + +int +_dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, + unsigned long rel_addr, + unsigned long rel_size) +{ + return _dl_parse(rpnt->dyn, scope, rel_addr, + rel_size, _dl_do_reloc); +} + diff --git a/ldso/ldso/nds32/resolve.S b/ldso/ldso/nds32/resolve.S new file mode 100644 index 000000000..8c53850d7 --- /dev/null +++ b/ldso/ldso/nds32/resolve.S @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) +# define STACK_PUSH +# define STACK_POP +#else +# define STACK_PUSH addi $sp, $sp, -24 +# define STACK_POP addi $sp, $sp, 24 +#endif + + .text + .align 4 ! 16 byte boundary + .globl _dl_linux_resolve + .type _dl_linux_resolve,#function + .pic + +_dl_linux_resolve: + ! we get called with + ! lp contains the return address from this call + ! r16 contains offset to target reloc entry + ! r17 contains GOT[1] (identity of taget lib) + ! ta is GOT[2] (starting address of this function) + + ! save arguments r0 - r5 and gp, lp + smw.adm $r0, [$sp], $r5, 6 + + ! init gp +#ifdef __NDS32_N1213_43U1H__ + sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $ta, $gp +#else + mfusr $ta, $PC + sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $ta, $gp +#endif + + ! #ifdef __NDS32_ABI_1__ + ! adjust stack + !addi $sp, $sp, -24 + STACK_PUSH + ! #endif + + ! set arguments + addi $r0, $r17, 0 + !addi $r1, $r16, 0 + slli $r1, $r16, 2 + slli $r16, $r16, 3 + add $r1, $r1, $r16 + + ! comment out profiling argument + !addi $r2, $lp, 0 + + ! call fixup routine + bal _dl_linux_resolver@PLT + + ! save the return + addi $ta, $r0, 0 + + ! #ifdef __NDS32_ABI_1__ + ! adjust sp + !addi $sp, $sp, 24 + STACK_POP + ! #endif + + ! reload registers + lmw.bim $r0, [$sp], $r5, 6 + + ! jump to the newly found address + jr $ta + +.size _dl_linux_resolve, .-_dl_linux_resolve -- cgit v1.2.3