diff --git a/bfd/config.bfd b/bfd/config.bfd
index a4c6c8e885..9edd7a0a15 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -238,6 +238,11 @@ esac
 case "${targ}" in
 # START OF targmatch.h
 #ifdef BFD64
+   aarch64-*-solaris2*)
+    targ_defvec=aarch64_elf64_le_vec
+    targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec"
+     want64=true
+     ;;
   aarch64-*-darwin*)
     targ_defvec=aarch64_mach_o_vec
     targ_selvecs="arm_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec"
diff --git a/bfd/configure b/bfd/configure
index 24531087d4..a0aed712a5 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13757,6 +13757,9 @@ CORE_HEADER=
 TRAD_HEADER=
 if test "${target}" = "${host}"; then
   case "${host}" in
+  aarch64*-*-solaris*)
+	COREFILE=''
+	;;
   alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-*vms*)
 	COREFILE=''
 	;;
@@ -13853,6 +13856,9 @@ if test "${target}" = "${host}"; then
   ns32k-*-netbsd* | ns32k-*-openbsd*)
 	COREFILE=netbsd-core.lo
 	;;
+  riscv64-*-solaris*)
+	COREFILE=''
+	;;
   rs6000-*-lynx*)
 	COREFILE=lynx-core.lo
 	;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 6146efb5ae..2f701a7f51 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -801,6 +801,9 @@ CORE_HEADER=
 TRAD_HEADER=
 if test "${target}" = "${host}"; then
   case "${host}" in
+  aarch64*-*-solaris*)
+	COREFILE=''
+	;;
   alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-*vms*)
 	COREFILE=''
 	;;
@@ -921,6 +924,9 @@ changequote([,])dnl
   ns32k-*-netbsd* | ns32k-*-openbsd*)
 	COREFILE=netbsd-core.lo
 	;;
+  riscv64-*-solaris*)
+	COREFILE=''
+	;;
   rs6000-*-lynx*)
 	COREFILE=lynx-core.lo
 	;;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 2b1450fa4e..5c51c67921 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -6954,6 +6954,11 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
 	      for (n = t->deps; n != NULL; n = n->next)
 		{
+		  if (n->version_needed_name) {
+			info->callbacks->einfo(_("%Xversion `%s' is not found\n"),
+			     n->version_needed_name);
+		  }
+		  BFD_ASSERT (n->version_needed_name == NULL);
 		  if (n->version_needed == NULL)
 		    {
 		      /* This can happen if there was an error in the
@@ -7321,7 +7326,11 @@ NOTE: This behaviour is deprecated and will be removed in a future version of th
 	  if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0))
 	    return false;
 	}
-
+      if (info->rtldinfo)
+      {
+	  if (!_bfd_elf_add_dynamic_entry (info, DT_SUNW_RTLDINF, 0))
+	    return false;
+      }
       s = bfd_get_section_by_name (output_bfd, ".preinit_array");
       if (s != NULL && s->linker_has_input)
 	{
@@ -13182,7 +13191,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 		  relr_entsize = 0;
 		}
 	      continue;
-
+	    case DT_SUNW_RTLDINF:
+	      name = info->rtldinfo_name;
+	      goto get_sym;
 	    case DT_INIT:
 	      name = info->init_function;
 	      goto get_sym;
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 251a27edb5..827722e7ee 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -9989,6 +9989,59 @@ const struct elf_size_info elfNN_aarch64_size_info =
   bfd_elfNN_swap_reloca_out
 };
 
+static int
+elfNN_aarch64_additional_program_headers (bfd *abfd,
+				       struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  asection *s;
+  int count = 0;
+
+  /* Check to see if we need a large readonly segment.  */
+  s = bfd_get_section_by_name (abfd, ".dtrace_data");
+  if (s && (s->flags & SEC_LOAD))
+    count++;
+
+  return count;
+}
+
+#define	PT_SUNWDTRACE	0x6ffffffc
+static bool
+elfNN_aarch64_modify_segment_map (bfd *abfd,
+    struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+	struct elf_segment_map *m;
+	asection *sec;
+
+	sec = bfd_get_section_by_name (abfd, ".dtrace_data");
+	if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
+	{
+		m = elf_seg_map (abfd);
+		while (m && m->p_type != PT_SUNWDTRACE)
+			m = m->next;
+
+		if (!m)
+		{
+			m = (struct elf_segment_map *) bfd_zalloc(abfd, sizeof (struct elf_segment_map));
+			if (m == NULL)
+				return false;
+			m->p_type = PT_SUNWDTRACE;
+			m->count = 1;
+			m->sections[0] = sec;
+			m->next = elf_seg_map (abfd);
+			elf_seg_map (abfd) = m;
+		}
+	}
+
+	return true;
+}
+
+static const struct bfd_elf_special_section
+  elfNN_aarch64_special_sections[]=
+{
+  { STRING_COMMA_LEN (".dtrace_data"),	    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_EXECINSTR},
+  { NULL,	                0,          0, 0,            0 }
+};
+
 #define ELF_ARCH			bfd_arch_aarch64
 #define ELF_MACHINE_CODE		EM_AARCH64
 #define ELF_MAXPAGESIZE			0x10000
@@ -10104,6 +10157,15 @@ const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_merge_gnu_properties	\
   elfNN_aarch64_merge_gnu_properties
 
+#define elf_backend_special_sections		\
+  elfNN_aarch64_special_sections
+
+#define elf_backend_modify_segment_map		\
+  elfNN_aarch64_modify_segment_map
+
+#define elf_backend_additional_program_headers	\
+  elfNN_aarch64_additional_program_headers
+
 #define elf_backend_can_refcount       1
 #define elf_backend_can_gc_sections    1
 #define elf_backend_plt_readonly       1
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 8f9f0d8a86..ec84f3e442 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -5169,9 +5169,16 @@ riscv_elf_additional_program_headers (bfd *abfd,
   if (bfd_get_section_by_name (abfd, RISCV_ATTRIBUTES_SECTION_NAME))
     ++ret;
 
+  /* Check to see if we need a large readonly segment.  */
+  asection *s = bfd_get_section_by_name (abfd, ".dtrace_data");
+  if (s && (s->flags & SEC_LOAD))
+    ++ret;
+
   return ret;
 }
 
+#define	PT_SUNWDTRACE	0x6ffffffc
+
 static bool
 riscv_elf_modify_segment_map (bfd *abfd,
 			      struct bfd_link_info *info ATTRIBUTE_UNUSED)
@@ -5213,6 +5220,26 @@ riscv_elf_modify_segment_map (bfd *abfd,
 	}
     }
 
+  asection *sec = bfd_get_section_by_name (abfd, ".dtrace_data");
+  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
+    {
+      m = elf_seg_map (abfd);
+      while (m && m->p_type != PT_SUNWDTRACE)
+	  m = m->next;
+
+      if (!m)
+	{
+	  m = (struct elf_segment_map *) bfd_zalloc(abfd, sizeof (struct elf_segment_map));
+	  if (m == NULL)
+		  return false;
+	  m->p_type = PT_SUNWDTRACE;
+	  m->count = 1;
+	  m->sections[0] = sec;
+	  m->next = elf_seg_map (abfd);
+	  elf_seg_map (abfd) = m;
+	}
+    }
+
   return true;
 }
 
@@ -5238,6 +5265,13 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
     h->other |= STO_RISCV_VARIANT_CC;
 }
 
+static const struct bfd_elf_special_section
+  riscv_elf_special_sections[]=
+{
+  { STRING_COMMA_LEN (".dtrace_data"),	    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_EXECINSTR},
+  { NULL,	                0,          0, 0,            0 }
+};
+
 #define TARGET_LITTLE_SYM			riscv_elfNN_vec
 #define TARGET_LITTLE_NAME			"elfNN-littleriscv"
 #define TARGET_BIG_SYM				riscv_elfNN_be_vec
@@ -5278,6 +5312,8 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
 
 #define elf_backend_init_index_section		_bfd_elf_init_1_index_section
 
+#define elf_backend_special_sections		riscv_elf_special_sections
+
 #define elf_backend_can_gc_sections		1
 #define elf_backend_can_refcount		1
 #define elf_backend_want_got_plt		1
diff --git a/gas/configure.tgt b/gas/configure.tgt
index 62f806bdfe..80e5a4d385 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -134,6 +134,7 @@ case ${generic_target} in
       aarch64*-linux-gnu_ilp32)		arch=aarch64:32 ;;
     esac ;;
   aarch64*-*-netbsd*)			fmt=elf em=nbsd;;
+  aarch64*-*-solaris*)			fmt=elf em=solaris ;;
 
   alpha-*-*vms*)			fmt=evax ;;
   alpha-*-osf*)				fmt=ecoff ;;
@@ -369,6 +370,7 @@ case ${generic_target} in
 
   pru-*-*)				fmt=elf ;;
 
+  riscv64-*-solaris*)		fmt=elf endian=little em=solaris ;;
   riscv*-*-haiku*)			fmt=elf endian=little em=haiku ;;
   riscv*-*-*)				fmt=elf ;;
 
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 961a3b9218..46d9212d38 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -257,7 +257,7 @@ get_debugseg_name (segT seg, const char *base_name)
   else
     name = dollar;
 
-  return concat (base_name, name, NULL);
+  return concat (base_name, name, (void *)0);
 }
 
 /* Allocate a dwcfi_seg_list structure.  */
diff --git a/gdb/aarch64-sol2-nat.c b/gdb/aarch64-sol2-nat.c
new file mode 100644
index 0000000000..527958d819
--- /dev/null
+++ b/gdb/aarch64-sol2-nat.c
@@ -0,0 +1,53 @@
+/* Native-dependent code for Solaris SPARC.
+
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "regcache.h"
+
+#include <sys/procfs.h>
+#include "gregset.h"
+
+#include "aarch64-tdep.h"
+#include "aarch64-sol2-tdep.h"
+#include "target.h"
+#include "procfs.h"
+
+void
+supply_gregset (struct regcache *regcache, const prgregset_t *gregs)
+{
+	regcache_supply_regset (&aarch64_sol2_gregset, regcache, -1, (const gdb_byte *) gregs, AARCH64_SOL2_SIZEOF_GREGSET);
+}
+
+void
+supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs)
+{
+	regcache_supply_regset (&aarch64_sol2_fpregset, regcache, -1, (const gdb_byte *) fpregs, AARCH64_SOL2_SIZEOF_FPREGSET);
+}
+
+void
+fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum)
+{
+	regcache_collect_regset (&aarch64_sol2_gregset, regcache, regnum, (gdb_byte *) gregs, AARCH64_SOL2_SIZEOF_GREGSET);
+}
+
+void
+fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, int regnum)
+{
+	regcache_collect_regset (&aarch64_sol2_fpregset, regcache, regnum, (gdb_byte *) fpregs, AARCH64_SOL2_SIZEOF_FPREGSET);
+}
diff --git a/gdb/aarch64-sol2-tdep.c b/gdb/aarch64-sol2-tdep.c
new file mode 100644
index 0000000000..7918e51f8d
--- /dev/null
+++ b/gdb/aarch64-sol2-tdep.c
@@ -0,0 +1,253 @@
+/* Target-dependent code for Newlib AArch64.
+
+   Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdbarch.h"
+#include "aarch64-tdep.h"
+#include "aarch64-sol2-tdep.h"
+#include "osabi.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "regset.h"
+#include "solib-svr4.h"
+#include "trad-frame.h"
+#include "sol2-tdep.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
+/* Register maps.  */
+
+static const struct regcache_map_entry aarch64_sol2_gregmap[] =
+  {
+    { 31, AARCH64_X0_REGNUM, 8 }, /* x0 ... x30 */
+    { 1, AARCH64_SP_REGNUM, 8 },
+    { 1, AARCH64_PC_REGNUM, 8 },
+    { 1, AARCH64_CPSR_REGNUM, 8 },
+    { 0 }
+  };
+
+static const struct regcache_map_entry aarch64_sol2_fpregmap[] =
+  {
+    { 32, AARCH64_V0_REGNUM, 16 }, /* v0 ... v31 */
+    { 1, AARCH64_FPCR_REGNUM, 4 },
+    { 1, AARCH64_FPSR_REGNUM, 4 },
+    { 0 }
+  };
+
+/* Register set definitions.  */
+
+const struct regset aarch64_sol2_gregset =
+  {
+    aarch64_sol2_gregmap,
+    regcache_supply_regset, regcache_collect_regset
+  };
+
+const struct regset aarch64_sol2_fpregset =
+  {
+    aarch64_sol2_fpregmap,
+    regcache_supply_regset, regcache_collect_regset
+  };
+
+/* Implement the "regset_from_core_section" gdbarch method.  */
+
+static void
+aarch64_sol2_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					    iterate_over_regset_sections_cb *cb,
+					    void *cb_data,
+					    const struct regcache *regcache)
+{
+  cb (".reg", AARCH64_SOL2_SIZEOF_GREGSET, AARCH64_SOL2_SIZEOF_GREGSET, &aarch64_sol2_gregset,
+      NULL, cb_data);
+  cb (".reg2", AARCH64_SOL2_SIZEOF_FPREGSET, AARCH64_SOL2_SIZEOF_FPREGSET, &aarch64_sol2_fpregset,
+      NULL, cb_data);
+}
+
+
+struct aarch64_frame_cache
+{
+  /* Base address.  */
+  CORE_ADDR base;
+  CORE_ADDR pc;
+
+  /* Do we have a frame?  */
+  int frameless_p;
+
+  /* The offset from the base register to the CFA.  */
+  int frame_offset;
+
+  /* Mask of `local' and `in' registers saved in the register save area.  */
+  unsigned short int saved_regs_mask;
+
+  /* Mask of `out' registers copied or renamed to their `in' sibling.  */
+  unsigned char copied_regs_mask;
+
+  /* Do we have a Structure, Union or Quad-Precision return value?  */
+  int struct_return_p;
+
+  /* Table of saved registers.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static CORE_ADDR
+aarch64_sol2_mcontext_addr (struct frame_info *this_frame)
+{
+  CORE_ADDR ucontext_addr;
+
+  ucontext_addr = get_frame_register_unsigned (this_frame, AARCH64_X0_REGNUM + 2);
+  return ucontext_addr + 8 * 7;
+}
+
+static struct aarch64_frame_cache *
+aarch64_alloc_frame_cache (void)
+{
+  struct aarch64_frame_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct aarch64_frame_cache);
+
+  /* Base address.  */
+  cache->base = 0;
+  cache->pc = 0;
+
+  /* Frameless until proven otherwise.  */
+  cache->frameless_p = 1;
+  cache->frame_offset = 0;
+  cache->saved_regs_mask = 0;
+  cache->copied_regs_mask = 0;
+  cache->struct_return_p = 0;
+
+  return cache;
+}
+
+static struct aarch64_frame_cache *
+aarch64_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
+				   void **this_cache)
+{
+  struct aarch64_frame_cache *cache;
+  CORE_ADDR mcontext_addr;
+  int regnum;
+
+  if (*this_cache)
+    return (aarch64_frame_cache*)*this_cache;
+
+  cache = aarch64_alloc_frame_cache ();
+  *this_cache = cache;
+
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  mcontext_addr = aarch64_sol2_mcontext_addr (this_frame);
+
+  for (regnum = 0; regnum < 31; regnum++)
+	  cache->saved_regs[regnum].set_addr(mcontext_addr + regnum * 8);
+  cache->saved_regs[AARCH64_SP_REGNUM].set_addr(mcontext_addr + 31 * 8);	// sp
+  cache->saved_regs[AARCH64_PC_REGNUM].set_addr(mcontext_addr + 32 * 8);	// pc
+  cache->saved_regs[AARCH64_CPSR_REGNUM].set_addr(mcontext_addr + 33 * 8);	// cpsr
+
+  for (regnum = 0; regnum < 32; regnum++)
+	  cache->saved_regs[regnum + AARCH64_V0_REGNUM].set_addr(mcontext_addr + 36 * 8 + regnum * 16);
+
+  cache->saved_regs[AARCH64_FPCR_REGNUM].set_addr(mcontext_addr + 36 * 8 + 32 * 16);
+  cache->saved_regs[AARCH64_FPSR_REGNUM].set_addr(mcontext_addr + 36 * 8 + 32 * 16 + 4);
+
+  return cache;
+}
+
+static void
+aarch64_sol2_sigtramp_frame_this_id (struct frame_info *this_frame,
+				     void **this_cache,
+				     struct frame_id *this_id)
+{
+  struct aarch64_frame_cache *cache =
+    aarch64_sol2_sigtramp_frame_cache (this_frame, this_cache);
+
+  (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static struct value *
+aarch64_sol2_sigtramp_frame_prev_register (struct frame_info *this_frame,
+					   void **this_cache,
+					   int regnum)
+{
+  struct aarch64_frame_cache *cache =
+    aarch64_sol2_sigtramp_frame_cache (this_frame, this_cache);
+
+  struct value *ret = trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+  return ret;
+}
+
+static int
+aarch64_sol2_sigtramp_frame_sniffer (const struct frame_unwind *self,
+				     struct frame_info *this_frame,
+				     void **this_cache)
+{
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  return (name && (strcmp ("sigacthandler", name) == 0 || strcmp (name, "ucbsigvechandler") == 0));
+}
+
+
+static const struct frame_unwind aarch64_sol2_sigtramp_frame_unwind =
+{
+  "aarch64 solaris sigtramp",
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  aarch64_sol2_sigtramp_frame_this_id,
+  aarch64_sol2_sigtramp_frame_prev_register,
+  NULL,
+  aarch64_sol2_sigtramp_frame_sniffer
+};
+
+
+/* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
+
+static void
+aarch64_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  tdep->lowest_pc = 0x8000;
+  tdep->jb_pc = 11;
+
+  frame_unwind_append_unwinder (gdbarch, &aarch64_sol2_sigtramp_frame_unwind);
+  sol2_init_abi (info, gdbarch);
+
+  /* Solaris has SVR4-style shared libraries...  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets);
+
+  /* Solaris has kernel-assisted single-stepping support.  */
+  /* Breakpoint manipulation.  */
+  set_gdbarch_software_single_step (gdbarch, NULL);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_aarch64_sol2_tdep;
+
+void
+_initialize_aarch64_sol2_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_SOLARIS,
+			  aarch64_sol2_init_abi);
+}
diff --git a/gdb/aarch64-sol2-tdep.h b/gdb/aarch64-sol2-tdep.h
new file mode 100644
index 0000000000..3592030fc6
--- /dev/null
+++ b/gdb/aarch64-sol2-tdep.h
@@ -0,0 +1,31 @@
+/* GNU/Linux on AArch64 target support, prototypes.
+
+   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "regset.h"
+
+/* X0 - X31, SP, PC, PSR, TP */
+#define AARCH64_SOL2_SIZEOF_GREGSET  (36 * X_REGISTER_SIZE)
+
+/* V0 - V31, FPCR, FPSR */
+#define AARCH64_SOL2_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE)
+
+extern const struct regset aarch64_sol2_gregset;
+extern const struct regset aarch64_sol2_fpregset;
+
diff --git a/gdb/config/aarch64/nm-sol2.h b/gdb/config/aarch64/nm-sol2.h
new file mode 100644
index 0000000000..bee367004e
--- /dev/null
+++ b/gdb/config/aarch64/nm-sol2.h
@@ -0,0 +1,26 @@
+/* Native-dependent definitions for Solaris AArch64.
+
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NM_SOL2_H
+#define NM_SOL2_H
+
+#define GDB_GREGSET_T prgregset_t
+#define GDB_FPREGSET_T prfpregset_t
+
+#endif /* nm-sol2.h */
diff --git a/gdb/config/riscv64/nm-sol2.h b/gdb/config/riscv64/nm-sol2.h
new file mode 100644
index 0000000000..90c663de94
--- /dev/null
+++ b/gdb/config/riscv64/nm-sol2.h
@@ -0,0 +1,26 @@
+/* Native-dependent definitions for Solaris RISC-V.
+
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NM_SOL2_H
+#define NM_SOL2_H
+
+#define GDB_GREGSET_T prgregset_t
+#define GDB_FPREGSET_T prfpregset_t
+
+#endif /* nm-sol2.h */
diff --git a/gdb/configure.host b/gdb/configure.host
index da71675b20..e98f88092f 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -81,6 +81,7 @@ case "${host}" in
 
 aarch64*-*-linux*)	gdb_host=linux ;;
 aarch64*-*-freebsd*)	gdb_host=fbsd ;;
+aarch64*-*-solaris2.1[0-9]*)	gdb_host=sol2 ;;
 
 alpha*-*-linux*)	gdb_host=alpha-linux ;;
 alpha*-*-netbsdaout* | alpha*-*-knetbsdaout*-gnu)
@@ -147,6 +148,7 @@ powerpc*-*-linux*)	gdb_host=linux ;;
 
 riscv*-*-freebsd*)	gdb_host=fbsd ;;
 riscv*-*-linux*)	gdb_host=linux ;;
+riscv*-*-solaris2.1[0-9]*)	gdb_host=sol2 ;;
 
 s390*-*-linux*)		gdb_host=linux ;;
 
diff --git a/gdb/configure.nat b/gdb/configure.nat
index d219d6a960..1177f3ad06 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -498,6 +498,16 @@ case ${gdb_host} in
 		NAT_FILE='nm-sol2.h'
 		NATDEPFILES="${NATDEPFILES} sparc-sol2-nat.o"
 		;;
+	    aarch64)
+		# Host: Solaris AArch64
+		NAT_FILE='nm-sol2.h'
+		NATDEPFILES="${NATDEPFILES} aarch64-sol2-nat.o"
+		;;
+	    riscv*)
+		# Host: Solaris RISC-V
+		NAT_FILE='nm-sol2.h'
+		NATDEPFILES="${NATDEPFILES} riscv-sol2-nat.o"
+		;;
 	esac
 	;;
 esac
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 0705ccf32b..ee59691912 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -144,6 +144,12 @@ aarch64*-*-linux*)
 			symfile-mem.o linux-record.o"
 	;;
 
+aarch64*-*-solaris2.1[0-9]*)
+	# Target: AArch64 Solaris
+	gdb_target_obs="aarch64-tdep.o aarch64-sol2-tdep.o arch/aarch64-insn.o arch/aarch64.o \
+			sol2-tdep.o solib-svr4.o ravenscar-thread.o aarch64-ravenscar-thread.o"
+	;;
+
 alpha*-*-linux*)
 	# Target: Little-endian Alpha running Linux
 	gdb_target_obs="alpha-mdebug-tdep.o alpha-linux-tdep.o \
@@ -535,6 +541,12 @@ riscv*-*-linux*)
  			linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
 	;;
 
+riscv*-*-solaris2.1[0-9]*)
+	# Target: RISC-V Solaris
+	gdb_target_obs="riscv-sol2-tdep.o \
+			sol2-tdep.o solib-svr4.o"
+	;;
+
 riscv*-*-*)
 	# Target: RISC-V architecture
 	gdb_target_obs=""
diff --git a/gdb/procfs.c b/gdb/procfs.c
index ffb4d18029..b5bd8b24d6 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -2155,7 +2155,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status,
 		      }
 		    else
 		      {
-			int temp = ::wait (&wstat);
+			int temp = ::waitpid(pi->pid, &wstat, 0);
 
 			/* FIXME: shouldn't I make sure I get the right
 			   event from the right process?  If (for
diff --git a/gdb/riscv-sol2-nat.c b/gdb/riscv-sol2-nat.c
new file mode 100644
index 0000000000..bff150ee1f
--- /dev/null
+++ b/gdb/riscv-sol2-nat.c
@@ -0,0 +1,57 @@
+/* Native-dependent code for Solaris SPARC.
+
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "regcache.h"
+
+#include <sys/procfs.h>
+#include "gregset.h"
+
+#include "riscv-tdep.h"
+#include "riscv-sol2-tdep.h"
+#include "target.h"
+#include "procfs.h"
+
+void
+supply_gregset (struct regcache *regcache, const prgregset_t *gregs)
+{
+	int xlen = register_size (regcache->arch(), RISCV_RA_REGNUM);
+	regcache_supply_regset (&riscv_sol2_gregset, regcache, -1, (const gdb_byte *) gregs, xlen * 32);
+}
+
+void
+supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs)
+{
+	int flen = register_size (regcache->arch(), RISCV_FIRST_FP_REGNUM);
+	regcache_supply_regset (&riscv_sol2_fpregset, regcache, -1, (const gdb_byte *) fpregs, flen * 32 + 8);
+}
+
+void
+fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum)
+{
+	int xlen = register_size (regcache->arch(), RISCV_RA_REGNUM);
+	regcache_collect_regset (&riscv_sol2_gregset, regcache, regnum, (gdb_byte *) gregs, xlen * 32);
+}
+
+void
+fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, int regnum)
+{
+	int flen = register_size (regcache->arch(), RISCV_FIRST_FP_REGNUM);
+	regcache_collect_regset (&riscv_sol2_fpregset, regcache, regnum, (gdb_byte *) fpregs, flen * 32 + 8);
+}
diff --git a/gdb/riscv-sol2-tdep.c b/gdb/riscv-sol2-tdep.c
new file mode 100644
index 0000000000..e827d743a0
--- /dev/null
+++ b/gdb/riscv-sol2-tdep.c
@@ -0,0 +1,248 @@
+/* Target-dependent code for Newlib AArch64.
+
+   Copyright (C) 2011-2014 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdbarch.h"
+#include "riscv-tdep.h"
+#include "riscv-sol2-tdep.h"
+#include "osabi.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "regset.h"
+#include "solib-svr4.h"
+#include "trad-frame.h"
+#include "sol2-tdep.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
+/* Register maps.  */
+
+static const struct regcache_map_entry riscv_sol2_gregmap[] =
+  {
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 0 }
+};
+
+static const struct regcache_map_entry riscv_sol2_fpregmap[] =
+  {
+  { 32, RISCV_FIRST_FP_REGNUM, 0 },
+  { 1, RISCV_CSR_FCSR_REGNUM, 0 },
+  { 0 }
+};
+
+/* Register set definitions.  */
+
+const struct regset riscv_sol2_gregset =
+  {
+    riscv_sol2_gregmap, regcache_supply_regset, regcache_collect_regset
+  };
+
+const struct regset riscv_sol2_fpregset =
+  {
+    riscv_sol2_fpregmap,
+    regcache_supply_regset, regcache_collect_regset
+  };
+
+/* Implement the "regset_from_core_section" gdbarch method.  */
+
+static void
+riscv_sol2_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					    iterate_over_regset_sections_cb *cb,
+					    void *cb_data,
+					    const struct regcache *regcache)
+{
+  cb (".reg", (32 * riscv_isa_xlen (gdbarch)), (32 * riscv_isa_xlen (gdbarch)),
+      &riscv_sol2_gregset, NULL, cb_data);
+  cb (".reg2", (32 * riscv_isa_flen (gdbarch)) + 8,
+      (32 * riscv_isa_flen (gdbarch)) + 8,
+      &riscv_sol2_fpregset, NULL, cb_data);
+}
+
+
+struct riscv_frame_cache
+{
+  /* Base address.  */
+  CORE_ADDR base;
+  CORE_ADDR pc;
+
+  /* Do we have a frame?  */
+  int frameless_p;
+
+  /* The offset from the base register to the CFA.  */
+  int frame_offset;
+
+  /* Mask of `local' and `in' registers saved in the register save area.  */
+  unsigned short int saved_regs_mask;
+
+  /* Mask of `out' registers copied or renamed to their `in' sibling.  */
+  unsigned char copied_regs_mask;
+
+  /* Do we have a Structure, Union or Quad-Precision return value?  */
+  int struct_return_p;
+
+  /* Table of saved registers.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static CORE_ADDR
+riscv_sol2_mcontext_addr (struct frame_info *this_frame)
+{
+  CORE_ADDR ucontext_addr;
+
+  ucontext_addr = get_frame_register_unsigned (this_frame, RISCV_A0_REGNUM + 2);
+  return ucontext_addr + 8 * 7;
+}
+
+static struct riscv_frame_cache *
+riscv_alloc_frame_cache (void)
+{
+  struct riscv_frame_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct riscv_frame_cache);
+
+  /* Base address.  */
+  cache->base = 0;
+  cache->pc = 0;
+
+  /* Frameless until proven otherwise.  */
+  cache->frameless_p = 1;
+  cache->frame_offset = 0;
+  cache->saved_regs_mask = 0;
+  cache->copied_regs_mask = 0;
+  cache->struct_return_p = 0;
+
+  return cache;
+}
+
+static struct riscv_frame_cache *
+riscv_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
+				   void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct riscv_frame_cache *cache;
+  CORE_ADDR mcontext_addr;
+  int regnum;
+  int xlen = riscv_isa_xlen (gdbarch);
+  int flen = riscv_isa_flen (gdbarch);
+
+  if (*this_cache)
+    return (riscv_frame_cache*)*this_cache;
+
+  cache = riscv_alloc_frame_cache ();
+  *this_cache = cache;
+
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  mcontext_addr = riscv_sol2_mcontext_addr (this_frame);
+
+  for (regnum = 0; regnum < 31; regnum++)
+	  cache->saved_regs[regnum].set_addr(mcontext_addr + regnum * xlen);
+  cache->saved_regs[RISCV_PC_REGNUM].set_addr(mcontext_addr + 31 * xlen);	// pc
+
+  for (regnum = 0; regnum < 32; regnum++)
+	  cache->saved_regs[regnum + RISCV_FIRST_FP_REGNUM].set_addr(mcontext_addr + 32 * xlen + regnum * flen);
+
+  cache->saved_regs[RISCV_CSR_FCSR_REGNUM].set_addr(mcontext_addr + 32 * xlen + 32 * flen);
+
+  return cache;
+}
+
+static void
+riscv_sol2_sigtramp_frame_this_id (struct frame_info *this_frame,
+				     void **this_cache,
+				     struct frame_id *this_id)
+{
+  struct riscv_frame_cache *cache =
+    riscv_sol2_sigtramp_frame_cache (this_frame, this_cache);
+
+  (*this_id) = frame_id_build (cache->base, cache->pc);
+}
+
+static struct value *
+riscv_sol2_sigtramp_frame_prev_register (struct frame_info *this_frame,
+					   void **this_cache,
+					   int regnum)
+{
+  struct riscv_frame_cache *cache =
+    riscv_sol2_sigtramp_frame_cache (this_frame, this_cache);
+
+  struct value *ret = trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+  return ret;
+}
+
+static int
+riscv_sol2_sigtramp_frame_sniffer (const struct frame_unwind *self,
+				     struct frame_info *this_frame,
+				     void **this_cache)
+{
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  return (name && (strcmp ("sigacthandler", name) == 0 || strcmp (name, "ucbsigvechandler") == 0));
+}
+
+
+static const struct frame_unwind riscv_sol2_sigtramp_frame_unwind =
+{
+  "riscv solaris sigtramp",
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  riscv_sol2_sigtramp_frame_this_id,
+  riscv_sol2_sigtramp_frame_prev_register,
+  NULL,
+  riscv_sol2_sigtramp_frame_sniffer
+};
+
+
+/* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
+
+static void
+riscv_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  frame_unwind_append_unwinder (gdbarch, &riscv_sol2_sigtramp_frame_unwind);
+  sol2_init_abi (info, gdbarch);
+
+  /* Solaris has SVR4-style shared libraries...  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					 (riscv_isa_xlen (gdbarch) == 4
+					  ? svr4_ilp32_fetch_link_map_offsets
+					  : svr4_lp64_fetch_link_map_offsets));
+
+  set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_riscv_sol2_tdep;
+
+void
+_initialize_riscv_sol2_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_SOLARIS,
+			  riscv_sol2_init_abi);
+}
diff --git a/gdb/riscv-sol2-tdep.h b/gdb/riscv-sol2-tdep.h
new file mode 100644
index 0000000000..6900818df2
--- /dev/null
+++ b/gdb/riscv-sol2-tdep.h
@@ -0,0 +1,25 @@
+/* GNU/Linux on AArch64 target support, prototypes.
+
+   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "regset.h"
+
+extern const struct regset riscv_sol2_gregset;
+extern const struct regset riscv_sol2_fpregset;
+
diff --git a/gnulib/import/string.in.h b/gnulib/import/string.in.h
index 33160b2525..6eafdf0b36 100644
--- a/gnulib/import/string.in.h
+++ b/gnulib/import/string.in.h
@@ -127,6 +127,8 @@ _GL_EXTERN_C void __cdecl free (void *);
 #  else
 #   if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
+#   elif defined __cplusplus && defined __sun__ && defined __GNUC__
+_GL_EXTERN_C void std::free (void *);
 #   else
 _GL_EXTERN_C void free (void *);
 #   endif
@@ -138,6 +140,8 @@ _GL_EXTERN_C void __cdecl free (void *);
 # else
 #  if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
+#  elif defined __cplusplus && defined __sun__ && defined __GNUC__
+_GL_EXTERN_C void std::free (void *);
 #  else
 _GL_EXTERN_C void free (void *);
 #  endif
diff --git a/gnulib/import/wchar.in.h b/gnulib/import/wchar.in.h
index 0d5c0b7abe..b19d917da1 100644
--- a/gnulib/import/wchar.in.h
+++ b/gnulib/import/wchar.in.h
@@ -190,6 +190,8 @@ _GL_EXTERN_C void __cdecl free (void *);
 #  else
 #   if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
+#   elif defined __cplusplus && defined __sun__ && defined __GNUC__
+_GL_EXTERN_C void std::free (void *);
 #   else
 _GL_EXTERN_C void free (void *);
 #   endif
@@ -201,6 +203,8 @@ _GL_EXTERN_C void __cdecl free (void *);
 # else
 #  if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
 _GL_EXTERN_C void free (void *) throw ();
+#  elif defined __cplusplus && defined __sun__ && defined __GNUC__
+_GL_EXTERN_C void std::free (void *);
 #  else
 _GL_EXTERN_C void free (void *);
 #  endif
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 09a3ec0168..c6e7465f90 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -554,6 +554,10 @@ struct bfd_link_info
   /* TRUE if commonpagesize is set on command-line.  */
   unsigned int commonpagesize_is_set : 1;
 
+  unsigned int rtldinfo: 1;
+
+  char *rtldinfo_name;
+
   /* Char that may appear as the first char of a symbol, but should be
      skipped (like symbol_leading_char) when looking up symbols in
      wrap_hash.  Used by PowerPC Linux for 'dot' symbols.  */
@@ -1038,6 +1042,7 @@ struct bfd_elf_version_deps
   struct bfd_elf_version_deps *next;
   /* The version which this version depends upon.  */
   struct bfd_elf_version_tree *version_needed;
+  const char *version_needed_name;
 };
 
 /* A node in the version tree.  */
diff --git a/include/elf/common.h b/include/elf/common.h
index e4bc53e35b..8b57a949c6 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -1176,6 +1176,8 @@
 #define DT_VERNEED	0x6ffffffe
 #define DT_VERNEEDNUM	0x6fffffff
 
+#define DT_SUNW_RTLDINF	0x6000000e
+
 /* This tag is a GNU extension to the Solaris version scheme.  */
 #define DT_VERSYM	0x6ffffff0
 
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 2bae9099b6..3d97c056e1 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -80,6 +80,8 @@ fi
 # Please try to keep this table more or less in alphabetic order - it
 # makes it much easier to lookup a specific archictecture.
 case "${targ}" in
+aarch64-*-solaris2*)	targ_emul=aarch64elf
+			targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" ;;
 aarch64_be-*-elf)	targ_emul=aarch64elfb
 			targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf"
 			;;
@@ -811,6 +813,7 @@ riscv64be*-*-linux*)	targ_emul=elf64briscv
 			targ_extra_emuls="elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32"
 			targ_extra_libpath=$targ_extra_emuls
 			;;
+riscv64-*-solaris2*)	targ_emul=elf64lriscv ;;
 riscv64*-*-linux*)	targ_emul=elf64lriscv
 			targ_extra_emuls="elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32 elf64briscv elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32"
 			targ_extra_libpath=$targ_extra_emuls
diff --git a/ld/emulparams/aarch64elf.sh b/ld/emulparams/aarch64elf.sh
index 8f68e517b4..92e5d1acda 100644
--- a/ld/emulparams/aarch64elf.sh
+++ b/ld/emulparams/aarch64elf.sh
@@ -12,16 +12,19 @@ NO_REL_RELOCS=yes
 TEMPLATE_NAME=elf
 EXTRA_EM_FILE=aarch64elf
 
+# SEPARATE_CODE=yes
+
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
 
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
 
 ENTRY=_start
 EMBEDDED=yes
 SEPARATE_GOTPLT=24
 IREL_IN_PLT=
-TEXT_START_ADDR=0x00400000
+TEXT_START_ADDR="0x00400000 + SIZEOF_HEADERS"
 
 DATA_START_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__data_start = .${CREATE_SHLIB+)};"
 
@@ -34,6 +37,7 @@ OTHER_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__end__ = .${CREATE_SHLIB+)};"
 
 OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }'
 ATTRS_SECTIONS='.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }'
+PLT=".plt          ${RELOCATING-0} : ALIGN(16) { *(.plt)${IREL_IN_PLT+ *(.iplt)} }"
 
 # This sets the stack to the top of the simulator memory (2^19 bytes).
 STACK_ADDR=0x80000
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 1968f12cf2..097f967019 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -60,9 +60,92 @@ fragment <<EOF
   link_info.default_execstack = DEFAULT_LD_EXECSTACK;
 }
 
+static struct bfd_link_needed_list *force_needed_top;
+
+static bool
+_bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *hash_table;
+
+  hash_table = elf_hash_table (info);
+  if (hash_table->dynobj == NULL)
+    hash_table->dynobj = abfd;
+
+  if (hash_table->dynstr == NULL)
+    {
+      hash_table->dynstr = _bfd_elf_strtab_init ();
+      if (hash_table->dynstr == NULL)
+	return false;
+    }
+  return true;
+}
+
+static void
+elf_add_dt_needed_tag (bfd *abfd,
+		       struct bfd_link_info *info,
+		       const char *soname,
+		       bool do_it)
+{
+  struct elf_link_hash_table *hash_table;
+  bfd_size_type oldsize;
+  bfd_size_type strindex;
+
+  if (!_bfd_elf_link_create_dynstrtab (abfd, info))
+    return;
+
+  hash_table = elf_hash_table (info);
+  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+  strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, false);
+  if (strindex == (bfd_size_type) -1)
+    return;
+
+  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
+    {
+      asection *sdyn;
+      const struct elf_backend_data *bed;
+      bfd_byte *extdyn;
+
+      bed = get_elf_backend_data (hash_table->dynobj);
+      sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+      if (sdyn != NULL)
+	for (extdyn = sdyn->contents;
+	     extdyn < sdyn->contents + sdyn->size;
+	     extdyn += bed->s->sizeof_dyn)
+	  {
+	    Elf_Internal_Dyn dyn;
+
+	    bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
+	    if (dyn.d_tag == DT_NEEDED
+		&& dyn.d_un.d_val == strindex)
+	      {
+		_bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+		return;
+	      }
+	  }
+    }
+
+  if (do_it)
+    {
+      if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+	return;
+
+      if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+	return;
+    }
+  else
+    /* We were just checking for existence of the tag.  */
+    _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+
+  return;
+}
 static void
 aarch64_elf_before_allocation (void)
 {
+  struct bfd_link_needed_list *entry = force_needed_top;
+  while (entry) {
+    elf_add_dt_needed_tag (link_info.output_bfd, &link_info, entry->name, true);
+    entry = entry->next;
+  }
   /* We should be able to set the size of the interworking stub section.  We
      can't do it until later if we have dynamic sections, though.  */
   if (! elf_hash_table (&link_info)->dynamic_sections_created)
@@ -363,6 +446,7 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_FIX_ERRATUM_835769	313
 #define OPTION_FIX_ERRATUM_843419	314
 #define OPTION_NO_APPLY_DYNAMIC_RELOCS	315
+#define OPTION_FORCE_ADD_NEEDED	316
 '
 
 PARSE_AND_LIST_SHORTOPTS=p
@@ -376,6 +460,7 @@ PARSE_AND_LIST_LONGOPTS='
   { "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769},
   { "fix-cortex-a53-843419", optional_argument, NULL, OPTION_FIX_ERRATUM_843419},
   { "no-apply-dynamic-relocs", no_argument, NULL, OPTION_NO_APPLY_DYNAMIC_RELOCS},
+  { "force-add-needed", required_argument, NULL, OPTION_FORCE_ADD_NEEDED },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -408,6 +493,7 @@ PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("  --no-apply-dynamic-relocs    Do not apply link-time values for dynamic relocations\n"));
   fprintf (file, _("  -z force-bti                  Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n"));
   fprintf (file, _("  -z pac-plt                    Protect PLTs with Pointer Authentication.\n"));
+  fprintf (file, _("  --force-add-needed=<dso>     Force add needed\n"));
 '
 
 PARSE_AND_LIST_ARGS_CASE_Z_AARCH64='
@@ -462,6 +548,25 @@ PARSE_AND_LIST_ARGS_CASES='
       no_apply_dynamic_relocs = 1;
       break;
 
+    case OPTION_FORCE_ADD_NEEDED:
+      {
+        struct bfd_link_needed_list *new_entry = xmalloc (sizeof (struct bfd_link_needed_list));
+	if (new_entry) {
+		new_entry->name = strdup(optarg);
+		new_entry->by = 0;
+		new_entry->next = 0;
+		struct bfd_link_needed_list *entry = force_needed_top;;
+		if (entry) {
+			while (entry->next)
+				entry = entry->next;
+			entry->next = new_entry;
+		} else {
+			force_needed_top = new_entry;
+		}
+	}
+      }
+      break;
+
     case OPTION_STUBGROUP_SIZE:
       {
 	const char *end;
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index c52484f35d..16712d434c 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -737,6 +737,11 @@ fragment <<EOF
 	link_info.unresolved_syms_in_objects = RM_IGNORE;
       else if (strcmp (optarg, "muldefs") == 0)
 	link_info.allow_multiple_definition = true;
+      else if (startswith (optarg, "rtldinfo=") && strlen(&optarg[9]))
+	{
+		link_info.rtldinfo = true;
+		link_info.rtldinfo_name = strdup(optarg + 9);
+	}
       else if (startswith (optarg, "max-page-size="))
 	{
 	  char *end;
diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em
index 645a807f23..b84acc56c6 100644
--- a/ld/emultempl/riscvelf.em
+++ b/ld/emultempl/riscvelf.em
@@ -25,9 +25,93 @@ fragment <<EOF
 #include "elf/riscv.h"
 #include "elfxx-riscv.h"
 
+static struct bfd_link_needed_list *force_needed_top;
+
+static bool
+_bfd_elf_link_create_dynstrtab (bfd *abfd, struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *hash_table;
+
+  hash_table = elf_hash_table (info);
+  if (hash_table->dynobj == NULL)
+    hash_table->dynobj = abfd;
+
+  if (hash_table->dynstr == NULL)
+    {
+      hash_table->dynstr = _bfd_elf_strtab_init ();
+      if (hash_table->dynstr == NULL)
+	return false;
+    }
+  return true;
+}
+
+static void
+elf_add_dt_needed_tag (bfd *abfd,
+		       struct bfd_link_info *info,
+		       const char *soname,
+		       bool do_it)
+{
+  struct elf_link_hash_table *hash_table;
+  bfd_size_type oldsize;
+  bfd_size_type strindex;
+
+  if (!_bfd_elf_link_create_dynstrtab (abfd, info))
+    return;
+
+  hash_table = elf_hash_table (info);
+  oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+  strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, false);
+  if (strindex == (bfd_size_type) -1)
+    return;
+
+  if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
+    {
+      asection *sdyn;
+      const struct elf_backend_data *bed;
+      bfd_byte *extdyn;
+
+      bed = get_elf_backend_data (hash_table->dynobj);
+      sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+      if (sdyn != NULL)
+	for (extdyn = sdyn->contents;
+	     extdyn < sdyn->contents + sdyn->size;
+	     extdyn += bed->s->sizeof_dyn)
+	  {
+	    Elf_Internal_Dyn dyn;
+
+	    bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
+	    if (dyn.d_tag == DT_NEEDED
+		&& dyn.d_un.d_val == strindex)
+	      {
+		_bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+		return;
+	      }
+	  }
+    }
+
+  if (do_it)
+    {
+      if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+	return;
+
+      if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+	return;
+    }
+  else
+    /* We were just checking for existence of the tag.  */
+    _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+
+  return;
+}
+
 static void
 riscv_elf_before_allocation (void)
 {
+  struct bfd_link_needed_list *entry = force_needed_top;
+  while (entry) {
+    elf_add_dt_needed_tag (link_info.output_bfd, &link_info, entry->name, true);
+    entry = entry->next;
+  }
   gld${EMULATION_NAME}_before_allocation ();
 
   if (link_info.discard == discard_sec_merge)
@@ -100,6 +184,43 @@ riscv_create_output_section_statements (void)
 
 EOF
 
+# Define some shell vars to insert bits of code into the standard elf
+# parse_args and list_options functions.
+#
+PARSE_AND_LIST_PROLOGUE='
+#define OPTION_FORCE_ADD_NEEDED	300
+'
+
+PARSE_AND_LIST_LONGOPTS='
+  { "force-add-needed", required_argument, NULL, OPTION_FORCE_ADD_NEEDED },
+'
+
+PARSE_AND_LIST_OPTIONS='
+  fprintf (file, _("\
+  --force-add-needed=<dso>    Force add needed\n"));
+'
+
+PARSE_AND_LIST_ARGS_CASES='
+    case OPTION_FORCE_ADD_NEEDED:
+      {
+        struct bfd_link_needed_list *new_entry = xmalloc (sizeof (struct bfd_link_needed_list));
+	if (new_entry) {
+		new_entry->name = strdup(optarg);
+		new_entry->by = 0;
+		new_entry->next = 0;
+		struct bfd_link_needed_list *entry = force_needed_top;;
+		if (entry) {
+			while (entry->next)
+				entry = entry->next;
+			entry->next = new_entry;
+		} else {
+			force_needed_top = new_entry;
+		}
+	}
+      }
+      break;
+'
+
 LDEMUL_BEFORE_ALLOCATION=riscv_elf_before_allocation
 LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
 LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=riscv_create_output_section_statements
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 3a904e3948..ea11373de4 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -154,7 +154,7 @@ static int error_index;
 %token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
-%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT SYMBOL_VERSION SYMBOL_SCOPE
 %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT
 %token EXCLUDE_FILE
 %token CONSTANT
@@ -1381,6 +1381,18 @@ vers_node:
 		{
 		  lang_register_vers_node (NULL, $2, NULL);
 		}
+	|	SYMBOL_SCOPE '{' vers_tag '}' ';'
+		{
+		  lang_register_vers_node (NULL, $3, NULL);
+		}
+	|	SYMBOL_VERSION VERS_TAG '{' vers_tag '}' ';'
+		{
+		  lang_register_vers_node ($2, $4, NULL);
+		}
+	|	SYMBOL_VERSION VERS_TAG '{' vers_tag '}' verdep ';'
+		{
+		  lang_register_vers_node ($2, $4, $6);
+		}
 	|	VERS_TAG '{' vers_tag '}' ';'
 		{
 		  lang_register_vers_node ($1, $3, NULL);
diff --git a/ld/ldlang.c b/ld/ldlang.c
index f12c09633a..4e4261f9f3 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -9465,9 +9465,41 @@ lang_register_vers_node (const char *name,
   else
     version->vernum = 0;
 
+  int vernum = version->vernum;
+  for (t = link_info.version_info; t != NULL; t = t->next) {
+	  struct bfd_elf_version_deps *ver_deps = t->deps;
+	  while (ver_deps) {
+		  if (ver_deps->version_needed_name &&
+		      strcmp (ver_deps->version_needed_name, name) == 0) {
+			  ver_deps->version_needed = version;
+			  free(ver_deps->version_needed_name);
+			  ver_deps->version_needed_name = NULL;
+			  if (t->vernum < vernum)
+				  vernum = t->vernum;
+		  }
+		  ver_deps = ver_deps->next;
+	  }
+  }
+
   for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next)
-    ;
+	  ;
   *pp = version;
+
+  while (vernum != version->vernum) {
+	  for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next) {
+		  if ((*pp)->next == version) {
+			  t = *pp;
+			  int v = t->vernum;
+			  t->vernum = version->vernum;
+			  version->vernum = v;
+
+			  t->next = version->next;
+			  version->next = t;
+			  *pp = version;
+			  break;
+		  }
+	  }
+  }
 }
 
 /* This is called when we see a version dependency.  */
@@ -9480,6 +9512,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
 
   ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
   ret->next = list;
+  ret->version_needed_name = NULL;
 
   for (t = link_info.version_info; t != NULL; t = t->next)
     {
@@ -9490,9 +9523,10 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
 	}
     }
 
-  einfo (_("%X%P: unable to find version dependency `%s'\n"), name);
+//  einfo (_("%X%P: unable to find version dependency `%s'\n"), name);
 
   ret->version_needed = NULL;
+  ret->version_needed_name = strdup(name);
   return ret;
 }
 
diff --git a/ld/ldlex.l b/ld/ldlex.l
index c38b46b933..a18410f55f 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -444,6 +444,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <SCRIPT,EXPRESSION,WILD,VERS_START,VERS_NODE,VERS_SCRIPT>#.* {
 				/* Eat up comments */ }
 
+<VERS_START,VERS_SCRIPT>$mapfile_version.*	{ /* Eat up comments */ }
+
 <VERS_NODE,VERS_SCRIPT>[:,;]	{ return *yytext; }
 
 <VERS_NODE>global		{ RTOKEN(GLOBAL); }
@@ -455,6 +457,10 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <VERS_NODE>{V_IDENTIFIER}	{ yylval.name = xstrdup (yytext);
 				  return VERS_IDENTIFIER; }
 
+<VERS_SCRIPT>SYMBOL_VERSION	{ RTOKEN(SYMBOL_VERSION); }
+
+<VERS_SCRIPT>SYMBOL_SCOPE	{ RTOKEN(SYMBOL_SCOPE); }
+
 <VERS_SCRIPT>{V_TAG}		{ yylval.name = xstrdup (yytext);
 				  return VERS_TAG; }
 
