[v5,04/11] nds32: Startup and Dynamic Loader

Message ID 1561012838-11352-5-git-send-email-vincentc@andestech.com
State Superseded
Headers

Commit Message

Vincent Chen June 20, 2019, 6:40 a.m. UTC
  This patch contains crti.S, crtn.S and the dynamic loader
for nds32 system.

2019-06-03  Vincent Chen  <vincentc@andestech.com>
2019-06-03  CheWei Chuang  <cnoize@andestech.com>

        * sysdeps/nds32/dl-machine.h: New file.
        * sysdeps/nds32/dl-sysdep.h: Likewise.
        * sysdeps/nds32/dl-trampoline.S: Likewise.
        * sysdeps/nds32/ldsodefs.h: Likewise.
        * sysdeps/nds32/start.S: Likewise.
        * sysdeps/unix/sysv/linux/nds32/dl-static.c: Likewise.
        * sysdeps/unix/sysv/linux/nds32/ldconfig.h: Likewise.
        * sysdeps/unix/sysv/linux/nds32/ldsodefs.h: Likewise.
---
 sysdeps/nds32/dl-machine.h                | 404 ++++++++++++++++++++++++++++++
 sysdeps/nds32/dl-sysdep.h                 |  22 ++
 sysdeps/nds32/dl-trampoline.S             | 164 ++++++++++++
 sysdeps/nds32/ldsodefs.h                  |  44 ++++
 sysdeps/nds32/start.S                     | 124 +++++++++
 sysdeps/unix/sysv/linux/nds32/dl-static.c |  84 +++++++
 sysdeps/unix/sysv/linux/nds32/ldconfig.h  |  27 ++
 sysdeps/unix/sysv/linux/nds32/ldsodefs.h  |  33 +++
 8 files changed, 902 insertions(+)
 create mode 100644 sysdeps/nds32/dl-machine.h
 create mode 100644 sysdeps/nds32/dl-sysdep.h
 create mode 100644 sysdeps/nds32/dl-trampoline.S
 create mode 100644 sysdeps/nds32/ldsodefs.h
 create mode 100644 sysdeps/nds32/start.S
 create mode 100644 sysdeps/unix/sysv/linux/nds32/dl-static.c
 create mode 100644 sysdeps/unix/sysv/linux/nds32/ldconfig.h
 create mode 100644 sysdeps/unix/sysv/linux/nds32/ldsodefs.h
  

Patch

diff --git a/sysdeps/nds32/dl-machine.h b/sysdeps/nds32/dl-machine.h
new file mode 100644
index 0000000..c418b34
--- /dev/null
+++ b/sysdeps/nds32/dl-machine.h
@@ -0,0 +1,404 @@ 
+/* Machine-dependent ELF dynamic relocation inline functions.
+   Andes nds32 version.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef dl_machine_h
+#define dl_machine_h
+
+#define ELF_MACHINE_NAME "NDS32"
+
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <ldsodefs.h>
+
+/* Return nonzero iff ELF header is compatible with the running host.  */
+static inline int __attribute__ ((unused))
+elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
+{
+  return ehdr->e_machine == EM_NDS32;
+}
+
+
+/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
+   first element of the GOT, a special entry that is never relocated.  */
+static inline ElfW(Addr) __attribute__ ((unused, const))
+elf_machine_dynamic (void)
+{
+  /* This produces a GOTOFF reloc that resolves to some offset at link time, so in
+     fact just loads from the GOT register directly.  By doing it without
+     an asm we can let the compiler choose any register.  */
+  extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
+  return _GLOBAL_OFFSET_TABLE_[0];
+}
+
+/* Return the run-time load address of the shared object.  */
+static inline ElfW(Addr) __attribute__ ((unused))
+elf_machine_load_address (void)
+{
+  /* Compute the difference between the runtime address of _DYNAMIC as seen
+     by a GOTOFF reference, and the link-time address found in the special
+     unrelocated first GOT entry.  */
+  extern ElfW(Dyn) bygotoff[] asm ("_DYNAMIC") attribute_hidden;
+  return (ElfW(Addr)) &bygotoff - elf_machine_dynamic ();
+}
+
+
+
+/* Set up the loaded object described by L so its unrelocated PLT
+   entries will jump to the on-demand fixup code in dl-runtime.c.  */
+
+static inline int __attribute__ ((unused, always_inline))
+elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+{
+  ElfW(Addr) *got;
+  extern void _dl_runtime_resolve (ElfW(Word)) attribute_hidden;
+  extern void _dl_runtime_profile (ElfW(Word)) attribute_hidden;
+
+  if (l->l_info[DT_JMPREL] && lazy)
+    {
+      /* The GOT entries for functions in the PLT have not yet been filled
+	 in.  Their initial contents will arrange when called to push an
+	 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
+	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
+      got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x28.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (ElfW(Addr)) &got[3];
+	}
+      got[1] = (ElfW(Addr)) l;	/* Identify this shared object.  */
+
+      /* The got[2] entry contains the address of a function which gets
+	 called to get the address of a so far unresolved function and
+	 jump to it.  The profiling extension of the dynamic linker allows
+	 to intercept the calls to collect information.  In this case we
+	 don't store the address in the GOT so that all future calls also
+	 end in this function.  */
+      if (__builtin_expect (profile, 0))
+	{
+	  got[2] = (ElfW(Addr)) &_dl_runtime_profile;
+
+	  if (GLRO(dl_profile) != NULL && _dl_name_match_p (GLRO(dl_profile), l))
+	    /* This is the object we are looking for.  Say that we really
+	       want profiling and the timers are started.  */
+	    GL(dl_profile_map) = l;
+	}
+      else
+	/* This function will get called to fix up the GOT entry indicated by
+	   the offset on the stack, and then jump to the resolved address.  */
+	got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
+    }
+
+  return lazy;
+}
+
+/* Initial entry point code for the dynamic linker.
+   The C function `_dl_start' is the real entry point;
+   its return value is the user program's entry point.  */
+#define RTLD_START asm ("						\
+	.text								\n\
+	.globl _start							\n\
+	.align	4							\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\
+	bal	_dl_start@PLT						\n\
+	/* Save user entry point in $r6 which is callee saved.  */	\n\
+	addi	$r6,	$r0,	0					\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				\n\
+	bnez	$r2,	2f						\n\
+	/* Prepare args to call _dl_init.  */				\n\
+	/* Get argv.  */						\n\
+	addi	$r2,	$sp,	4					\n\
+1:									\n\
+	l.w	$r0,	_rtld_local@GOTOFF				\n\
+	/* Get argc.  */						\n\
+	lwi	$r1,	[$sp+0]						\n\
+	/* envp =sp +argc * 4 + 8.  */					\n\
+	slli	$r3,	$r1,	2                                       \n\
+	addi	$r3,	$r3,	8					\n\
+	/* Get envp.  */						\n\
+	add	$r3,	$r3,	$sp					\n\
+	bal	_dl_init@PLT						\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\
+2:									\n\
+	lwi	$r0,	[$sp+0]						\n\
+	/* Offset for new $sp.  */					\n\
+	slli	$r1,	$r2,	2					\n\
+	/* Adjust sp to skip args.  */					\n\
+	add	$sp,	$sp,	$r1					\n\
+	/* Set and save new argc.  */					\n\
+	sub	$r0,	$r0,	$r2					\n\
+	swi	$r0,	[$sp+0]						\n\
+	andi	$r0,	$sp,	7					\n\
+	beqz	$r0,	1b						\n\
+									\n\
+	/* Make stack 8-byte aligned.  */				\n\
+	bitci	$sp,	$sp,	7					\n\
+	move	$r2,	$sp						\n\
+3:	/* argc and argv.  */						\n\
+	lwi	$r0,	[$r2+4]						\n\
+	smw.bim $r0,[$r2],$r0,#0					\n\
+	bnez	$r0,	3b						\n\
+									\n\
+3:	/* envp.  */							\n\
+	lwi	$r0,	[$r2+4]						\n\
+	smw.bim $r0,[$r2],$r0,#0					\n\
+	bnez	$r0,	3b						\n\
+									\n\
+3:	/* auxv.  */							\n\
+	lmw.ai	$r0,[$r2],$r1,#0					\n\
+	smw.bim	$r0,[$r2],$r1,#0					\n\
+	bnez	$r0,	3b						\n\
+									\n\
+	/* Update _dl_argv.  */						\n\
+	addi	$r2,	$sp,	4					\n\
+	s.w	$r2,	_dl_argv@GOTOFF					\n\
+	j	1b							\n\
+	.previous							\n\
+");
+
+# define elf_machine_type_class(type) 					\
+  (((((type) == R_NDS32_JMP_SLOT) 					\
+      || ((type)== R_NDS32_TLS_TPOFF) 					\
+      || ((type)== R_NDS32_TLS_DESC)) * ELF_RTYPE_CLASS_PLT)		\
+   | (((type) == R_NDS32_COPY) * ELF_RTYPE_CLASS_COPY) 			\
+   | (((type) == R_NDS32_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
+
+
+/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
+#define ELF_MACHINE_JMP_SLOT	R_NDS32_JMP_SLOT
+
+/* nds32 uses ElfW(Rela) no ElfW(Rel).  */
+#define ELF_MACHINE_NO_REL 1
+#define ELF_MACHINE_NO_RELA 0
+
+/* We define an initialization functions.  This is called very early in
+   _dl_sysdep_start.  */
+#define DL_PLATFORM_INIT dl_platform_init ()
+
+static inline void __attribute__ ((unused))
+dl_platform_init (void)
+{
+  /* Avoid an empty string which would disturb us.  */
+  if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
+    GLRO(dl_platform) = NULL;
+}
+
+/* Fixup a PLT entry to bounce directly to the function at VALUE.  */
+static inline ElfW(Addr)
+elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
+		       const ElfW(Rela) *reloc,
+		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
+{
+  return *reloc_addr = value;
+}
+
+static inline ElfW(Addr)
+elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
+		       ElfW(Addr) value)
+{
+  return value + reloc->r_addend ;
+}
+
+/* Names of the architecture-specific auditing callback functions.  */
+#define ARCH_LA_PLTENTER nds32_gnu_pltenter
+#define ARCH_LA_PLTEXIT nds32_gnu_pltexit
+
+#endif /* dl_machine_h.  */
+
+
+#ifdef RESOLVE_MAP
+
+# define COPY_UNALIGNED_WORD(swp, twp) \
+  { \
+    unsigned int __tmp = __builtin_nds32_unaligned_load_w (swp); \
+    __builtin_nds32_unaligned_store_w (twp, __tmp); \
+  }
+/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
+   MAP is the object containing the reloc.  */
+
+auto inline void
+elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+                  const ElfW(Sym) *sym, const struct r_found_version *version,
+                  void *const reloc_addr_arg, int skip_ifunc)
+{
+
+  ElfW(Addr) *const reloc_addr = reloc_addr_arg;
+  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+  ElfW(Addr) value = 0;
+
+  const ElfW(Sym) *const refsym = sym;
+  struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+  if (sym_map != NULL)
+    value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
+  switch (r_type)
+    {
+    case R_NDS32_COPY:
+      if (__glibc_unlikely (sym == NULL))
+        /* This can happen in trace mode if an object could not be
+           found.  */
+        break;
+      if (sym->st_size > refsym->st_size
+	      || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
+	{
+	  const char *strtab;
+
+	  strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
+	  _dl_error_printf ("\
+  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
+	                        rtld_progname ?: "<program name unknown>",
+				strtab + refsym->st_name);
+	}
+      memcpy (reloc_addr_arg, (void *) value,
+                MIN (sym->st_size, refsym->st_size));
+      break;
+    case R_NDS32_GLOB_DAT:
+    case R_NDS32_JMP_SLOT:
+      *reloc_addr = value;
+      break;
+    case R_NDS32_32_RELA:
+      COPY_UNALIGNED_WORD (&value, reloc_addr);
+      break;
+    case R_NDS32_TLS_TPOFF:
+      {
+# ifdef RTLD_BOOTSTRAP
+	*reloc_addr = map->l_tls_offset + sym->st_value + reloc->r_addend;
+# else
+	if (sym != NULL)
+	  {
+            CHECK_STATIC_TLS (map, sym_map);
+            *reloc_addr = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
+          }
+        else
+          _dl_error_printf ("sym is NULL in R_NDS32_TLS_TPOFF\n");
+# endif
+      }
+      break;
+
+    case R_NDS32_TLS_DESC:
+      {
+        struct tlsdesc volatile *td = (struct tlsdesc volatile *) reloc_addr;
+# ifndef RTLD_BOOTSTRAP
+	if (!sym)
+	  {
+	    td->argument.value = reloc->r_addend;
+	    td->entry = _dl_tlsdesc_undefweak;
+	  }
+	else
+# endif /* !RTLD_BOOTSTRAP */
+	  {
+	    value = sym->st_value + reloc->r_addend;
+# ifndef RTLD_BOOTSTRAP
+#   ifndef SHARED
+	    CHECK_STATIC_TLS (map, sym_map);
+#   else
+	    if (!TRY_STATIC_TLS (map, sym_map))
+	      {
+	        td->argument.pointer
+                  = _dl_make_tlsdesc_dynamic (sym_map, value);
+	        td->entry = _dl_tlsdesc_dynamic;
+	      }
+	    else
+#   endif /* SHARED */
+# endif /* !RTLD_BOOTSTRAP */
+	      {
+	        td->argument.value = value + sym_map->l_tls_offset;
+	        td->entry = _dl_tlsdesc_return;
+	      }
+	  }
+      }
+      break;
+# if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
+    case R_NDS32_RELATIVE:
+      {
+#  if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
+#   ifndef SHARED
+        weak_extern (_dl_rtld_map);
+#   endif
+        /* Already done in rtld itself.  */
+	if (map != &GL(dl_rtld_map))
+#  endif
+	  *reloc_addr = map->l_addr + reloc->r_addend;
+      }
+# endif
+    case R_NDS32_NONE:
+      break;
+    default:
+      _dl_reloc_bad_type (map, r_type, 0);
+      break;
+    }
+}
+
+auto inline void
+__attribute__ ((always_inline))
+elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+			   void *const reloc_addr_arg)
+{
+  ElfW(Addr) value;
+
+  if (reloc->r_addend)
+    value = l_addr + reloc->r_addend;
+  else
+    {
+      COPY_UNALIGNED_WORD (reloc_addr_arg, &value);
+      value += l_addr;
+    }
+  COPY_UNALIGNED_WORD (&value, reloc_addr_arg);
+
+# undef COPY_UNALIGNED_WORD
+}
+
+auto inline void
+__attribute__ ((always_inline))
+elf_machine_lazy_rel (struct link_map *map,
+		      ElfW(Addr) l_addr, const ElfW(Rela) *reloc, int skip_ifunc)
+{
+  ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
+  /* Check for unexpected PLT reloc type.  */
+  if (ELF32_R_TYPE (reloc->r_info) == R_NDS32_JMP_SLOT)
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((ElfW(Addr)) reloc_addr) - map->l_mach.gotplt) * 6;
+    }
+  else if (ELF32_R_TYPE (reloc->r_info) != R_NDS32_NONE)
+    _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
+}
+#endif /* RESOLVE_MAP */
+
diff --git a/sysdeps/nds32/dl-sysdep.h b/sysdeps/nds32/dl-sysdep.h
new file mode 100644
index 0000000..c7fc3d0
--- /dev/null
+++ b/sysdeps/nds32/dl-sysdep.h
@@ -0,0 +1,22 @@ 
+/* System-specific settings for dynamic linker code.  Andes nds32 version.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include_next <dl-sysdep.h>
+
+#define DL_ARGV_NOT_RELRO 1
+#define DL_EXTERN_PROTECTED_DATA
diff --git a/sysdeps/nds32/dl-trampoline.S b/sysdeps/nds32/dl-trampoline.S
new file mode 100644
index 0000000..ccd0a6e
--- /dev/null
+++ b/sysdeps/nds32/dl-trampoline.S
@@ -0,0 +1,164 @@ 
+/* PLT trampolines.  Andes nds32 version.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <libc-symbols.h>
+
+ENTRY (_dl_runtime_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).
+	   $r15 is GOT[2] (starting address of _dl_runtime_resolve).  */
+
+	/* Save arguments $r0 - $r3.  */
+	smw.adm $r0,	[$sp],	$r5,	6
+	.cfi_adjust_cfa_offset 32
+	.cfi_rel_offset lp, 28 
+	.cfi_rel_offset gp, 24
+
+	GET_GTABLE ($gp)
+
+	move	$r0,	$r17
+	/* Sizeof (ElfW(Rela)) is 12.  */
+	slli    $r1,    $r16,   2
+	slli    $r16,   $r16,   3
+	add     $r1,    $r1,    $r16
+	addi	$r2,	$lp,	0
+	bal	_dl_fixup
+	/* Save the return.  */
+	addi	$r15,	$r0,	0
+	
+	lmw.bim	$r0,	[$sp],	$r5,	6
+	.cfi_adjust_cfa_offset -32
+	.cfi_restore lp
+	.cfi_restore gp
+
+	/* Jump to the newly found address.  */
+	jr		$r15
+END (_dl_runtime_resolve)
+ENTRY (_dl_runtime_profile)
+
+	/* 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).
+	   $r15 is GOT[2] (starting address of this function).
+
+	   Stack layout:
+	   12 - La_nds32_regs (9 registers).
+	   4 - Saved two arguments to _dl_profile_fixup.
+	   0 - framesize returned from pltenter.  */
+
+	/* Save La_nds32_regs arguments: $r0 - $r5, $gp, $lp, $sp.  */
+	move 	$r15,	$sp
+	smw.adm $r0,	[$r15],	$r5,	7
+	move	$sp,	$r15
+	.cfi_adjust_cfa_offset 36
+	.cfi_rel_offset gp, 24
+	.cfi_rel_offset lp, 28
+
+	GET_GTABLE ($gp)
+
+	addi	$r0,	$r17,	0
+	slli	$r1,	$r16,	2
+	slli	$r16,	$r16,	3
+	add	$r1,	$r1,	$r16
+
+	smw.adm $r0,    [$sp],  $r1,    0
+	.cfi_adjust_cfa_offset 4
+
+	xor	$r4,	$r4,	$r4
+	push	$r4
+
+	move	$r2,	$lp
+	addi	$r3,	$sp,	12
+	move	$r4,	$sp
+
+	bal	_dl_profile_fixup
+	lw	$r2,	[$sp]
+	sw	$r0,	[$sp]
+	bgez	$r2,	1f
+	cfi_remember_state
+
+	addi	$r15,	$sp,	12
+	lmw.bim	$r0,	[$r15],	$r5,	7
+	.cfi_adjust_cfa_offset -48
+	.cfi_restore gp
+	.cfi_restore lp
+	lwi	$r15,	[$sp + (-48)]
+
+	/* Jump to the newly found address.  */
+	jr	$r15
+1:
+	/* The new frame size is in $r2.
+
+	   New stack layout:
+	   16 - La_nds32_regs (9 registers).
+	   8 - Saved two arguments to _dl_profile_fixup.
+	   4 - Saved result of _dl_profile_fixup.
+	   0 - saved $r6.  */
+
+	cfi_restore_state
+	push	$r6
+
+	/* Make new frame size 8-byte aligned.  */
+	bitci	$r6,	$r2,	7
+
+
+	/* Copy stack argument.  */
+	sub	$r0,	$sp,	$r6
+	addi	$r1,	$sp,	48
+	bal	memcpy
+
+	/* Jump to the newly found address.  */
+	addi	$r15,	$sp,	16
+	lmw.bim	$r0,	[$r15],	$r5,	0
+	lwi	$r15,	[$sp +4]
+	sub	$sp,	$sp,	$r6
+	jral	$r15
+	add	$sp,	$sp,	$r6
+	pop	$r6	
+	cfi_def_cfa_register (sp)
+	/* New stack layout:
+	   24 - La_nds32_regs (9 registers).
+	   16 - Saved two arguments to _dl_profile_fixup.
+	   12 - Saved result of _dl_profile_fixup.
+	   8 - one dummy word for stack aligned.
+	   0 - La_nds32_retval.  */
+	
+	/* Push $r0, $r1 for La_nds32_retval.  */
+	/* Push $r2 for dummy word.  */
+	smw.adm	$r0,	[$sp],	$r2
+	.cfi_adjust_cfa_offset 12
+	addi	$r15,	$sp,	16
+	lmw.bim $r0,    [$r15],  $r1	
+	addi	$r2,	$sp,	24
+	/* $r3 contains outregs.  */
+	move	$r3,	$sp
+	bal	_dl_call_pltexit
+
+	lmw.bim $r0,    [$sp],  $r1
+	addi	$r15,	$sp,	24
+	lmw.bim	$r2,	[$r15],	$r5,	7
+	.cfi_adjust_cfa_offset -48
+	.cfi_restore gp
+	.cfi_restore lp
+	ret
+END (_dl_runtime_profile)
diff --git a/sysdeps/nds32/ldsodefs.h b/sysdeps/nds32/ldsodefs.h
new file mode 100644
index 0000000..8df2ac8
--- /dev/null
+++ b/sysdeps/nds32/ldsodefs.h
@@ -0,0 +1,44 @@ 
+/* Run-time dynamic linker data structures for loaded ELF shared objects.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef	_NDS32_LDSODEFS_H
+#define	_NDS32_LDSODEFS_H	1
+
+#include <elf.h>
+
+struct La_nds32_regs;
+struct La_nds32_retval;
+
+#define ARCH_PLTENTER_MEMBERS						\
+    ElfW(Addr) (*nds32_gnu_pltenter) (ElfW(Sym) *, unsigned int, 	\
+				      uintptr_t *, uintptr_t *,		\
+				      struct La_nds32_regs *,		\
+				      unsigned int *, const char *name,	\
+				      long int *framesizep)
+
+#define ARCH_PLTEXIT_MEMBERS						\
+    unsigned int (*nds32_gnu_pltexit) (ElfW(Sym) *, unsigned int,	\
+				       uintptr_t *, uintptr_t *,	\
+				       const struct La_nds32_regs *,	\
+				       struct La_nds32_retval *, 	\
+				       const char *)
+
+#include_next <ldsodefs.h>
+
+#endif /* _NDS32_LDSODEFS_H.  */
diff --git a/sysdeps/nds32/start.S b/sysdeps/nds32/start.S
new file mode 100644
index 0000000..3135c10
--- /dev/null
+++ b/sysdeps/nds32/start.S
@@ -0,0 +1,124 @@ 
+/* Startup code compliant to the ELF nds32 ABI.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.
+
+	Note that the code in the .init section has already been run.
+	This includes _init and _libc_init
+
+
+	At this entry point, most registers' values are unspecified, except:
+
+   $r5		Contains a function pointer to be registered with `atexit'.
+		This is how the dynamic linker arranges to have DT_FINI
+		functions called for shared libraries that have been loaded
+		before this code runs.
+
+   sp		The stack contains the arguments and environment:
+		0(sp)			argc
+		4(sp)			argv[0]
+		...
+		(4*argc)(sp)		NULL
+		(4*(argc+1))(sp)	envp[0]
+		...
+					NULL
+*/
+#include <sysdep.h>
+	.text
+	.align	4
+	.globl _start
+	.type  _start, @function
+#ifdef SHARED
+	.pic
+#endif
+_start:
+	/* clear FP.  */
+	movi    $fp,	0
+	/* $r1 = argc.  */
+	lwi	$r1,	[$sp + 0]
+	/* $r2 = argv.  */
+	addi	$r2,	$sp,	4
+	
+	/* align sp to 8-byte boundary.  */
+	movi	$r0,	-8
+	and	$sp,	$sp,	$r0
+	/* $r6 = stack top.  */
+	addi	$r6,	$sp,	0
+	
+#ifdef SHARED
+	/* set $gp register.  */
+	GET_GTABLE ($gp)
+	
+	la	$r3,	__libc_csu_init@GOTOFF
+	la	$r4,	__libc_csu_fini@GOTOFF
+	la	$r0,	main@GOT
+	
+	/* push everything to stack.
+           $r5 is rtld_fini, $r7 is used to keep stack align.  */
+	pushm	$r0,	$r7
+	
+	/* now start it up.  */
+	bal	__libc_start_main@PLT
+	
+	/* should never get here.  */
+	bal	abort@PLT
+#else
+	/* init $gp for small data access.  */
+	la	$gp, _SDA_BASE_
+	
+	la	$r3,	__libc_csu_init
+	la 	$r4,	__libc_csu_fini
+	la	$r0,	main
+	
+	/* push everything to stack, $r5 is rtld_fini, $r7 is dummy a word.  */
+	pushm	$r0,	$r7
+	
+	/* now start it up.  */
+	bal	__libc_start_main
+	
+	/* should never get here.  */
+	bal	abort
+#endif /* !SHARED */
+
+	ret
+	
+	/* Define a symbol for the first piece of initialized data.  */
+	.data
+	.globl __data_start
+__data_start:
+	.long	0
+	.weak data_start
+	data_start = __data_start
diff --git a/sysdeps/unix/sysv/linux/nds32/dl-static.c b/sysdeps/unix/sysv/linux/nds32/dl-static.c
new file mode 100644
index 0000000..09864a7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nds32/dl-static.c
@@ -0,0 +1,84 @@ 
+/* Variable initialization, Andes nds32 version.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+
+#ifdef SHARED
+
+void
+_dl_var_init (void *array[])
+{
+  /* It has to match "variables" below.  */
+  enum
+    {
+      DL_PAGESIZE = 0
+    };
+
+  GLRO(dl_pagesize) = *((size_t *) array[DL_PAGESIZE]);
+}
+
+#else
+
+static void *variables[] =
+{
+  &GLRO(dl_pagesize)
+};
+
+static void
+_dl_unprotect_relro (struct link_map *l)
+{
+  ElfW(Addr) start = ((l->l_addr + l->l_relro_addr)
+		      & ~(GLRO(dl_pagesize) - 1));
+  ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size)
+		    & ~(GLRO(dl_pagesize) - 1));
+
+  if (start != end)
+    __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE);
+}
+
+void
+_dl_static_init (struct link_map *l)
+{
+  struct link_map *rtld_map = l;
+  struct r_scope_elem **scope;
+  const ElfW(Sym) *ref = NULL;
+  lookup_t loadbase;
+  void (*f) (void *[]);
+  size_t i;
+
+  loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope,
+				  NULL, 0, 1, NULL);
+
+  for (scope = l->l_local_scope; *scope != NULL; scope++)
+    for (i = 0; i < (*scope)->r_nlist; i++)
+      if ((*scope)->r_list[i] == loadbase)
+	{
+	  rtld_map = (*scope)->r_list[i];
+	  break;
+	}
+
+  if (ref != NULL)
+    {
+      f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref);
+      _dl_unprotect_relro (rtld_map);
+      f (variables);
+      _dl_protect_relro (rtld_map);
+    }
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/nds32/ldconfig.h b/sysdeps/unix/sysv/linux/nds32/ldconfig.h
new file mode 100644
index 0000000..51e567e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nds32/ldconfig.h
@@ -0,0 +1,27 @@ 
+/* ldconfig default paths and libraries, Andes Linux/nds32 version.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdeps/generic/ldconfig.h>
+
+
+#define SYSDEP_KNOWN_INTERPRETER_NAMES				\
+  { "/lib/ld-linux-nds32le.so.1", FLAG_ELF_LIBC6 }
+
+#define SYSDEP_KNOWN_LIBRARY_NAMES	\
+  { "libc.so.6", FLAG_ELF_LIBC6 },	\
+  { "libm.so.6", FLAG_ELF_LIBC6 },
diff --git a/sysdeps/unix/sysv/linux/nds32/ldsodefs.h b/sysdeps/unix/sysv/linux/nds32/ldsodefs.h
new file mode 100644
index 0000000..435e0e3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nds32/ldsodefs.h
@@ -0,0 +1,33 @@ 
+/* Andes nds32 dynamic linker data structures for loaded ELF shared objects.
+   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LDSODEFS_H
+
+
+/* Get the real definitions.  */
+#include_next <ldsodefs.h>
+
+/* Now define our stuff.  */
+
+/* We need special support to initialize DSO loaded for statically linked
+   binaries.  */
+extern void _dl_static_init (struct link_map *map);
+#undef DL_STATIC_INIT
+#define DL_STATIC_INIT(map) _dl_static_init (map)
+
+#endif /* _LDSODEFS_H */