[v2,03/15] RISC-V: Startup and Dynamic Loading Code

Message ID 20171220072022.26909-4-palmer@dabbelt.com
State New, archived
Headers

Commit Message

Palmer Dabbelt Dec. 20, 2017, 7:20 a.m. UTC
  This patch contains the various bits of support used by the C startup
code and the dynamic loader when running on a RISC-V system.  This
contains the implementation of our PLT entries, various ld.so hooks, and
_start.  This does not contain any Linux-specific code.
---
 sysdeps/riscv/bits/link.h   |  56 ++++++++
 sysdeps/riscv/crti.S        |  32 +++++
 sysdeps/riscv/dl-machine.h  | 308 ++++++++++++++++++++++++++++++++++++++++++++
 sysdeps/riscv/ldsodefs.h    |  47 +++++++
 sysdeps/riscv/linkmap.h     |   4 +
 sysdeps/riscv/sotruss-lib.c |  51 ++++++++
 sysdeps/riscv/start.S       |  80 ++++++++++++
 sysdeps/riscv/tst-audit.h   |  23 ++++
 8 files changed, 601 insertions(+)
 create mode 100644 sysdeps/riscv/bits/link.h
 create mode 100644 sysdeps/riscv/crti.S
 create mode 100644 sysdeps/riscv/dl-machine.h
 create mode 100644 sysdeps/riscv/ldsodefs.h
 create mode 100644 sysdeps/riscv/linkmap.h
 create mode 100644 sysdeps/riscv/sotruss-lib.c
 create mode 100644 sysdeps/riscv/start.S
 create mode 100644 sysdeps/riscv/tst-audit.h
  

Comments

Joseph Myers Dec. 20, 2017, 4:38 p.m. UTC | #1
On Tue, 19 Dec 2017, Palmer Dabbelt wrote:

> +extern ElfW(Addr) la_riscv_gnu_pltenter (ElfW(Sym) *__sym, unsigned int __ndx,

With reference to my previous comments, ElfW is an exception to the rule 
of spaces before '(' in macro and function calls, because it locally 
expands to a single identifier.  So this code is correct not to have a 
space there.

> +  extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__((visibility("hidden")));

However, __attribute__ is *not* an exception.  This should use:
__attribute__ ((visibility ("hidden"))) - and likewise for other 
attributes, elsewhere in this patch or the patch series as a whole.

General question in the area of this patch: static PIE support was 
recently added to glibc.  Do you support it for RISC-V?  It's not so far a 
requirement for adding a port, but if not supported, when the port goes in 
it would need adding to the list at 
<https://sourceware.org/glibc/wiki/PortStatus> of ports for which static 
PIE is not yet known to work.
  
Palmer Dabbelt Dec. 23, 2017, 3:24 a.m. UTC | #2
On Wed, 20 Dec 2017 08:38:48 PST (-0800), joseph@codesourcery.com wrote:
> On Tue, 19 Dec 2017, Palmer Dabbelt wrote:
>
>> +extern ElfW(Addr) la_riscv_gnu_pltenter (ElfW(Sym) *__sym, unsigned int __ndx,
>
> With reference to my previous comments, ElfW is an exception to the rule
> of spaces before '(' in macro and function calls, because it locally
> expands to a single identifier.  So this code is correct not to have a
> space there.
>
>> +  extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__((visibility("hidden")));

Ah, luckily I missed those when going through you last mail :)

>
> However, __attribute__ is *not* an exception.  This should use:
> __attribute__ ((visibility ("hidden"))) - and likewise for other
> attributes, elsewhere in this patch or the patch series as a whole.

Ah, thanks -- I'd missed these too.

> General question in the area of this patch: static PIE support was
> recently added to glibc.  Do you support it for RISC-V?  It's not so far a
> requirement for adding a port, but if not supported, when the port goes in
> it would need adding to the list at
> <https://sourceware.org/glibc/wiki/PortStatus> of ports for which static
> PIE is not yet known to work.

I haven't tried it, so I assume it does not work.  It looks like the static PIE 
section's header is broken on that site, I'm seeing

    == Static PIE ===

in normal text.  I assume it's supposed to look more like "=== Static PIE ===" 
to make the text large?

Based on looking through the requirement list, there's enough things there in 
toolchain land that "should just work" that I'm sure something will end up 
being broken.  I assume it's OK to just add the various RISC-V targets to the 
unsupported list for now?
  
Joseph Myers Dec. 23, 2017, 12:52 p.m. UTC | #3
On Fri, 22 Dec 2017, Palmer Dabbelt wrote:

> On Wed, 20 Dec 2017 08:38:48 PST (-0800), joseph@codesourcery.com wrote:
> > On Tue, 19 Dec 2017, Palmer Dabbelt wrote:
> > 
> > > +extern ElfW(Addr) la_riscv_gnu_pltenter (ElfW(Sym) *__sym, unsigned int
> > > __ndx,
> > 
> > With reference to my previous comments, ElfW is an exception to the rule
> > of spaces before '(' in macro and function calls, because it locally
> > expands to a single identifier.  So this code is correct not to have a
> > space there.
> > 
> > > +  extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_
> > > __attribute__((visibility("hidden")));
> 
> Ah, luckily I missed those when going through you last mail :)

I advise reading 
<https://sourceware.org/glibc/wiki/Style_and_Conventions>, which discusses 
exceptions such as ElfW and GLRO.

> I haven't tried it, so I assume it does not work.  It looks like the static
> PIE section's header is broken on that site, I'm seeing
> 
>    == Static PIE ===
> 
> in normal text.  I assume it's supposed to look more like "=== Static PIE ==="
> to make the text large?

If you don't already have wiki write access you should create an account 
and ask on libc-alpha for someone to add it to 
<https://sourceware.org/glibc/wiki/EditorGroup>.  Then you can fix typos 
yourself, as well as adding RISC-V entries to wiki pages where 
appropriate.

> Based on looking through the requirement list, there's enough things there in
> toolchain land that "should just work" that I'm sure something will end up
> being broken.  I assume it's OK to just add the various RISC-V targets to the
> unsupported list for now?

Yes (once in glibc).  RISC-V entries will also be needed on the list of 
ABIs and dynamic linker names at 
<https://sourceware.org/glibc/wiki/ABIList> - again, only once actually in 
glibc.

Apart from those wiki pages mentioned just now, every release cycle, 
during the one-month release freeze, architecture maintainers should add 
test results to the per-release wiki page (see 
<https://sourceware.org/glibc/wiki/Release/2.26> for the last release as 
an example, <https://sourceware.org/glibc/wiki/Release/2.27> for the next 
one, <https://sourceware.org/glibc/wiki/Release/X.Y> for the template 
for future releases which RISC-V will need adding to once in glibc).
  

Patch

diff --git a/sysdeps/riscv/bits/link.h b/sysdeps/riscv/bits/link.h
new file mode 100644
index 000000000000..067f2298e115
--- /dev/null
+++ b/sysdeps/riscv/bits/link.h
@@ -0,0 +1,56 @@ 
+/* Machine-specific declarations for dynamic linker interface.  RISC-V version.
+   Copyright (C) 2005-2017 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	_LINK_H
+# error "Never include <bits/link.h> directly; use <link.h> instead."
+#endif
+
+typedef struct La_riscv_regs
+{
+  unsigned long lr_reg[8]; /* a0 - a7 */
+  double lr_fpreg[8]; /* fa0 - fa7 */
+  unsigned long lr_ra;
+  unsigned long lr_sp;
+} La_riscv_regs;
+
+/* Return values for calls from PLT on RISC-V.  */
+typedef struct La_riscv_retval
+{
+  unsigned long lrv_a0;
+  unsigned long lrv_a1;
+  double lrv_fa0;
+  double lrv_fa1;
+} La_riscv_retval;
+
+__BEGIN_DECLS
+
+extern ElfW(Addr) la_riscv_gnu_pltenter (ElfW(Sym) *__sym, unsigned int __ndx,
+					 uintptr_t *__refcook,
+					 uintptr_t *__defcook,
+					 La_riscv_regs *__regs,
+					 unsigned int *__flags,
+					 const char *__symname,
+					 long int *__framesizep);
+extern unsigned int la_riscv_gnu_pltexit (ElfW(Sym) *__sym, unsigned int __ndx,
+					  uintptr_t *__refcook,
+					  uintptr_t *__defcook,
+					  const La_riscv_regs *__inregs,
+					  La_riscv_retval *__outregs,
+					  const char *__symname);
+
+__END_DECLS
diff --git a/sysdeps/riscv/crti.S b/sysdeps/riscv/crti.S
new file mode 100644
index 000000000000..c28222578ef0
--- /dev/null
+++ b/sysdeps/riscv/crti.S
@@ -0,0 +1,32 @@ 
+/* Facilitate pthread initialization using init_array.
+   Copyright (C) 2017 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 <sys/asm.h>
+
+#ifdef PREINIT_FUNCTION
+
+#if PREINIT_FUNCTION_WEAK
+# error PREINIT_FUNCTION_WEAK is unsupported
+#endif
+
+	.section .init_array, "aw"
+	.dc.a PREINIT_FUNCTION
+
+#endif
diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
new file mode 100644
index 000000000000..520882159783
--- /dev/null
+++ b/sysdeps/riscv/dl-machine.h
@@ -0,0 +1,308 @@ 
+/* Machine-dependent ELF dynamic relocation inline functions.  RISC-V version.
+   Copyright (C) 2011-2017 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 "RISC-V"
+
+#include <entry.h>
+#include <elf/elf.h>
+#include <sys/asm.h>
+#include <dl-tls.h>
+
+#ifndef _RTLD_PROLOGUE
+# define _RTLD_PROLOGUE(entry)						\
+	".globl\t" __STRING(entry) "\n\t"				\
+	".type\t" __STRING(entry) ", @function\n"			\
+	__STRING(entry) ":\n\t"
+#endif
+
+#ifndef _RTLD_EPILOGUE
+# define _RTLD_EPILOGUE(entry)						\
+	".size\t" __STRING(entry) ", . - " __STRING(entry) "\n\t"
+#endif
+
+#define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT
+
+#define elf_machine_type_class(type)				\
+  ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT	\
+     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPREL32)	\
+     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPMOD32)	\
+     || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32)	\
+     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64)	\
+     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64)	\
+     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64)))	\
+   | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
+
+#define ELF_MACHINE_NO_REL 1
+#define ELF_MACHINE_NO_RELA 0
+
+/* Return nonzero iff ELF header is compatible with the running host.  */
+static inline int __attribute_used__
+elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
+{
+  return ehdr->e_machine == EM_RISCV;
+}
+
+/* Return the link-time address of _DYNAMIC.  */
+static inline ElfW(Addr)
+elf_machine_dynamic (void)
+{
+  extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__((visibility("hidden")));
+  return _GLOBAL_OFFSET_TABLE_;
+}
+
+#define STRINGXP(X) __STRING(X)
+#define STRINGXV(X) STRINGV_(X)
+#define STRINGV_(...) # __VA_ARGS__
+
+/* Return the run-time load address of the shared object.  */
+static inline ElfW(Addr)
+elf_machine_load_address (void)
+{
+  ElfW(Addr) load_addr;
+  asm ("lla %0, _DYNAMIC" : "=r"(load_addr));
+  return load_addr - elf_machine_dynamic ();
+}
+
+/* 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\
+	" _RTLD_PROLOGUE(ENTRY_POINT) "\
+	mv a0, sp\n\
+	jal _dl_start\n\
+	# Stash user entry point in s0.\n\
+	mv s0, a0\n\
+	# See if we were run as a command with the executable file\n\
+	# name as an extra leading argument.\n\
+	lw a0, _dl_skip_args\n\
+	# Load the original argument count.\n\
+	" STRINGXP(REG_L) " a1, 0(sp)\n\
+	# Subtract _dl_skip_args from it.\n\
+	sub a1, a1, a0\n\
+	# Adjust the stack pointer to skip _dl_skip_args words.\n\
+	sll a0, a0, " STRINGXP (PTRLOG) "\n\
+	add sp, sp, a0\n\
+	# Save back the modified argument count.\n\
+	" STRINGXP(REG_S) " a1, 0(sp)\n\
+	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
+	" STRINGXP(REG_L) " a0, _rtld_local\n\
+	add a2, sp, " STRINGXP (SZREG) "\n\
+	sll a3, a1, " STRINGXP (PTRLOG) "\n\
+	add a3, a3, a2\n\
+	add a3, a3, " STRINGXP (SZREG) "\n\
+	# Call the function to run the initializers.\n\
+	jal _dl_init\n\
+	# Pass our finalizer function to _start.\n\
+	lla a0, _dl_fini\n\
+	# Jump to the user entry point.\n\
+	jr s0\n\
+	" _RTLD_EPILOGUE(ENTRY_POINT) "\
+	.previous" \
+);
+
+/* Names of the architecture-specific auditing callback functions.  */
+#define ARCH_LA_PLTENTER riscv_gnu_pltenter
+#define ARCH_LA_PLTEXIT riscv_gnu_pltexit
+
+/* Bias .got.plt entry by the offset requested by the PLT header. */
+#define elf_machine_plt_value(map, reloc, value) (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;
+}
+
+#endif /* !dl_machine_h */
+
+#ifdef RESOLVE_MAP
+
+/* Perform a relocation described by R_INFO at the location pointed to
+   by RELOC_ADDR.  SYM is the relocation symbol specified by R_INFO and
+   MAP is the object containing the reloc.  */
+
+auto inline void
+__attribute__ ((always_inline))
+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, int skip_ifunc)
+{
+  ElfW(Addr) r_info = reloc->r_info;
+  const unsigned long int r_type = ELFW(R_TYPE) (r_info);
+  ElfW(Addr) *addr_field = (ElfW(Addr) *) reloc_addr;
+  const ElfW(Sym) *const __attribute__((unused)) refsym = sym;
+  struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+  ElfW(Addr) value = 0;
+  if (sym_map != NULL)
+    value = sym_map->l_addr + sym->st_value + reloc->r_addend;
+
+  switch (r_type)
+    {
+#ifndef RTLD_BOOTSTRAP
+    case __WORDSIZE == 64 ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32:
+      if (sym_map)
+	*addr_field = sym_map->l_tls_modid;
+      break;
+
+    case __WORDSIZE == 64 ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32:
+      if (sym != NULL)
+	*addr_field = TLS_DTPREL_VALUE (sym) + reloc->r_addend;
+      break;
+
+    case __WORDSIZE == 64 ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32:
+      if (sym != NULL)
+	{
+	  CHECK_STATIC_TLS (map, sym_map);
+	  *addr_field = TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend;
+	}
+      break;
+
+    case R_RISCV_COPY:
+      {
+	if (__builtin_expect (sym == NULL, 0))
+	  /* This can happen in trace mode if an object could not be
+	     found.  */
+	  break;
+
+	/* Handle TLS copy relocations.  */
+	if (__glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_TLS))
+	  {
+	    /* There's nothing to do if the symbol is in .tbss.  */
+	    if (__glibc_likely (sym->st_value >= sym_map->l_tls_initimage_size))
+	      break;
+	    value += (ElfW(Addr)) sym_map->l_tls_initimage - sym_map->l_addr;
+	  }
+
+	size_t size = sym->st_size;
+	if (__builtin_expect (sym->st_size != refsym->st_size, 0))
+	  {
+	    const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+	    if (sym->st_size > refsym->st_size)
+	      size = refsym->st_size;
+	    if (sym->st_size > refsym->st_size || GLRO(dl_verbose))
+	      _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, (void *)value, size);
+	break;
+      }
+#endif
+
+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
+    case R_RISCV_RELATIVE:
+      {
+# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
+	/* This is defined in rtld.c, but nowhere in the static libc.a;
+	   make the reference weak so static programs can still link.
+	   This declaration cannot be done when compiling rtld.c
+	   (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+	   common defn for _dl_rtld_map, which is incompatible with a
+	   weak decl in the same file.  */
+#  ifndef SHARED
+	weak_extern (GL(dl_rtld_map));
+#  endif
+	if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
+# endif
+	  *addr_field = map->l_addr + reloc->r_addend;
+      break;
+    }
+#endif
+
+    case R_RISCV_JUMP_SLOT:
+    case __WORDSIZE == 64 ? R_RISCV_64 : R_RISCV_32:
+      *addr_field = value;
+      break;
+
+    case R_RISCV_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)
+{
+  *(ElfW(Addr) *)reloc_addr = l_addr + reloc->r_addend;
+}
+
+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);
+  const unsigned int r_type = ELFW(R_TYPE) (reloc->r_info);
+
+  /* Check for unexpected PLT reloc type.  */
+  if (__builtin_expect (r_type == R_RISCV_JUMP_SLOT, 1))
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	{
+	  if (l_addr)
+	    *reloc_addr += l_addr;
+	}
+      else
+	*reloc_addr = map->l_mach.plt;
+    }
+  else
+    _dl_reloc_bad_type (map, r_type, 1);
+}
+
+/* Set up the loaded object described by L so its stub function
+   will jump to the on-demand fixup code __dl_runtime_resolve.  */
+
+auto inline int
+__attribute__((always_inline))
+elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+{
+#ifndef RTLD_BOOTSTRAP
+  /* If using PLTs, fill in the first two entries of .got.plt.  */
+  if (l->l_info[DT_JMPREL])
+    {
+      extern void _dl_runtime_resolve (void) __attribute__((visibility("hidden")));
+      ElfW(Addr) *gotplt = (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 the address of .plt for us here.  */
+      if (gotplt[1])
+	l->l_mach.plt = gotplt[1] + l->l_addr;
+      gotplt[0] = (ElfW(Addr)) &_dl_runtime_resolve;
+      gotplt[1] = (ElfW(Addr)) l;
+    }
+#endif
+
+  return lazy;
+}
+
+#endif /* RESOLVE_MAP */
diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h
new file mode 100644
index 000000000000..db993df80a9a
--- /dev/null
+++ b/sysdeps/riscv/ldsodefs.h
@@ -0,0 +1,47 @@ 
+/* Run-time dynamic linker data structures for loaded ELF shared objects.
+   Copyright (C) 2011-2017 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 _RISCV_LDSODEFS_H
+#define _RISCV_LDSODEFS_H 1
+
+#include <elf.h>
+
+struct La_riscv_regs;
+struct La_riscv_retval;
+
+#define ARCH_PLTENTER_MEMBERS						\
+    Elf64_Addr (*riscv_gnu_pltenter) (Elf64_Sym *, unsigned int,	\
+				      uintptr_t *, uintptr_t *,		\
+				      const struct La_riscv_regs *,	\
+				      unsigned int *, const char *name,	\
+				      long int *framesizep);
+
+#define ARCH_PLTEXIT_MEMBERS						\
+    unsigned int (*riscv_gnu_pltexit) (Elf64_Sym *, unsigned int,	\
+				       uintptr_t *, uintptr_t *,	\
+				       const struct La_riscv_regs *,	\
+				       struct La_riscv_retval *,	\
+				       const char *);
+
+/* The RISC-V ABI specifies that the dynamic section has to be read-only.  */
+
+#define DL_RO_DYN_SECTION 1
+
+#include_next <ldsodefs.h>
+
+#endif
diff --git a/sysdeps/riscv/linkmap.h b/sysdeps/riscv/linkmap.h
new file mode 100644
index 000000000000..a6df7821e675
--- /dev/null
+++ b/sysdeps/riscv/linkmap.h
@@ -0,0 +1,4 @@ 
+struct link_map_machine
+  {
+    ElfW(Addr) plt; /* Address of .plt */
+  };
diff --git a/sysdeps/riscv/sotruss-lib.c b/sysdeps/riscv/sotruss-lib.c
new file mode 100644
index 000000000000..ef57f6885a96
--- /dev/null
+++ b/sysdeps/riscv/sotruss-lib.c
@@ -0,0 +1,51 @@ 
+/* Override generic sotruss-lib.c to define actual functions for RISC-V.
+   Copyright (C) 2012-2017 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/>.  */
+
+#define HAVE_ARCH_PLTENTER
+#define HAVE_ARCH_PLTEXIT
+
+#include <elf/sotruss-lib.c>
+
+ElfW(Addr)
+la_riscv_gnu_pltenter (ElfW(Sym) *sym __attribute__ ((unused)),
+		       unsigned int ndx __attribute__ ((unused)),
+		       uintptr_t *refcook, uintptr_t *defcook,
+		       La_riscv_regs *regs, unsigned int *flags,
+		       const char *symname, long int *framesizep)
+{
+  print_enter (refcook, defcook, symname,
+	       regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2],
+	       *flags);
+
+  /* No need to copy anything, we will not need the parameters in any case.  */
+  *framesizep = 0;
+
+  return sym->st_value;
+}
+
+unsigned int
+la_riscv_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+		      uintptr_t *defcook,
+		      const struct La_riscv_regs *inregs,
+		      struct La_riscv_retval *outregs,
+		      const char *symname)
+{
+  print_exit (refcook, defcook, symname, outregs->lrv_a0);
+
+  return 0;
+}
diff --git a/sysdeps/riscv/start.S b/sysdeps/riscv/start.S
new file mode 100644
index 000000000000..5438ae2886b2
--- /dev/null
+++ b/sysdeps/riscv/start.S
@@ -0,0 +1,80 @@ 
+/* Startup code compliant to the ELF RISC-V ABI.
+   Copyright (C) 1995-2017 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/>.  */
+
+#define __ASSEMBLY__ 1
+#include <entry.h>
+#include <sysdep.h>
+#include <sys/asm.h>
+
+/* The entry point's job is to call __libc_start_main.  Per the ABI,
+   a0 contains the address of a function to be passed to atexit.
+   __libc_start_main wants this in a5.  */
+
+ENTRY(ENTRY_POINT)
+	call  .Lload_gp
+	mv    a5, a0  /* rtld_fini */
+	lla   a0, main
+	REG_L a1, 0(sp)      /* argc */
+	addi  a2, sp, SZREG  /* argv */
+	andi  sp, sp, ALMASK /* Align stack. */
+	lla   a3, __libc_csu_init
+	lla   a4, __libc_csu_fini
+	mv    a6, sp  /* stack_end */
+
+	tail  __libc_start_main@plt
+END(ENTRY_POINT)
+
+/* Dynamic links need the global pointer to be initialized prior to calling
+   any shared library's initializers, so we use preinit_array to load it.
+   This doesn't cut it for static links, though, since the global pointer
+   needs to be initialized before calling __libc_start_main in that case.
+   So we redundantly initialize it at the beginning of _start.  */
+
+.Lload_gp:
+.option push
+.option norelax
+	lla   gp, __global_pointer$
+.option pop
+	ret
+
+	.section .preinit_array,"aw"
+	.dc.a .Lload_gp
+
+/* Define a symbol for the first piece of initialized data.  */
+	.data
+	.globl __data_start
+__data_start:
+	.weak data_start
+	data_start = __data_start
diff --git a/sysdeps/riscv/tst-audit.h b/sysdeps/riscv/tst-audit.h
new file mode 100644
index 000000000000..d49d577f68a6
--- /dev/null
+++ b/sysdeps/riscv/tst-audit.h
@@ -0,0 +1,23 @@ 
+/* Definitions for testing PLT entry/exit auditing.  RISC-V version.
+   Copyright (C) 2005-2017 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/>.  */
+
+#define pltenter la_riscv_gnu_pltenter
+#define pltexit la_riscv_gnu_pltexit
+#define La_regs La_riscv_regs
+#define La_retval La_riscv_retval
+#define int_retval lrv_a0