summaryrefslogtreecommitdiff
path: root/ldso/ldso
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2016-04-21 01:25:29 +0200
committerWaldemar Brodkorb <wbx@uclibc-ng.org>2016-06-30 03:24:42 +0200
commitee92c0fe5c1b9d59508273916e2c9a75b68dbc13 (patch)
tree65a22258b12f84325910fc2ad47e2b02696ef593 /ldso/ldso
parentdd46699e46decb7273f44dc2cbf307f096dc39e8 (diff)
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 <wbx@uclibc-ng.org>
Diffstat (limited to 'ldso/ldso')
-rw-r--r--ldso/ldso/nds32/dl-debug.h25
-rw-r--r--ldso/ldso/nds32/dl-startup.h175
-rw-r--r--ldso/ldso/nds32/dl-syscalls.h11
-rw-r--r--ldso/ldso/nds32/dl-sysdep.h99
-rw-r--r--ldso/ldso/nds32/elfinterp.c315
-rw-r--r--ldso/ldso/nds32/resolve.S76
6 files changed, 701 insertions, 0 deletions
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 <elf.h>
+/* 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<<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) = 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