diff --git a/ld/Makefile.am b/ld/Makefile.am
index c3adbb0ccad..8b7d3170a03 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -237,6 +237,7 @@ ALL_EMULATION_SOURCES = \
 	eelf32ip2k.c \
 	eelf32iq10.c \
 	eelf32iq2000.c \
+	eelf32kvx.c \
 	eelf32lm32.c \
 	eelf32lm32fd.c \
 	eelf32lppc.c \
@@ -448,6 +449,8 @@ ALL_64_EMULATION_SOURCES = \
 	eelf64lriscv_lp64f.c \
 	eelf64ltsmip.c \
 	eelf64ltsmip_fbsd.c \
+	eelf64kvx.c \
+	eelf64kvx_linux.c \
 	eelf64mmix.c \
 	eelf64ppc.c \
 	eelf64ppc_fbsd.c \
@@ -735,6 +738,7 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): $(GEN_DEPENDS)
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ip2k.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32iq10.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32iq2000.Pc@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32kvx.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lm32.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lm32fd.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppc.Pc@am__quote@
@@ -937,6 +941,8 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): $(GEN_DEPENDS)
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc_fbsd.Pc@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx_linux.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64loongarch.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lriscv.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lriscv_lp64.Pc@am__quote@
diff --git a/ld/Makefile.in b/ld/Makefile.in
index d1a56026437..4d16e6b08d7 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -738,6 +738,7 @@ ALL_EMULATION_SOURCES = \
 	eelf32ip2k.c \
 	eelf32iq10.c \
 	eelf32iq2000.c \
+	eelf32kvx.c \
 	eelf32lm32.c \
 	eelf32lm32fd.c \
 	eelf32lppc.c \
@@ -948,6 +949,8 @@ ALL_64_EMULATION_SOURCES = \
 	eelf64lriscv_lp64f.c \
 	eelf64ltsmip.c \
 	eelf64ltsmip_fbsd.c \
+	eelf64kvx.c \
+	eelf64kvx_linux.c \
 	eelf64mmix.c \
 	eelf64ppc.c \
 	eelf64ppc_fbsd.c \
@@ -1373,6 +1376,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ip2k.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32iq10.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32iq2000.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32kvx.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32l4300.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lm32.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lm32fd.Po@am__quote@
@@ -1443,6 +1447,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip_fbsd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx_linux.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64loongarch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc_fbsd.Po@am__quote@
@@ -2619,6 +2625,7 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): $(GEN_DEPENDS)
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ebmipvxworks.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32elmip.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32elmipvxworks.Pc@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32kvx.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32l4300.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32loongarch.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lmip.Pc@am__quote@
@@ -2652,6 +2659,8 @@ $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES): $(GEN_DEPENDS)
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip_fbsd.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Pc@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx_linux.Pc@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64kvx.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc_fbsd.Pc@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64loongarch.Pc@am__quote@
diff --git a/ld/configure b/ld/configure
index cab1c04d264..5de334b2004 100755
--- a/ld/configure
+++ b/ld/configure
@@ -11625,7 +11625,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11628 "configure"
+#line 11633 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11731,7 +11731,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11734 "configure"
+#line 11739 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/ld/configure.tgt b/ld/configure.tgt
index 4a71f679e29..6030b3f9878 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -473,6 +473,11 @@ lm32-*-*linux*)		targ_emul=elf32lm32fd
 lm32-*-*)		targ_emul=elf32lm32
 			targ_extra_emuls="elf32lm32fd"
 			;;
+kvx-*-linux*)		targ_emul=elf64kvx_linux
+			targ_extra_emuls="elf64kvx"
+			;;
+kvx-*-*)		targ_emul=elf64kvx; targ_extra_emuls="elf64kvx_linux elf32kvx"
+			;;
 m32c-*-elf)
 			targ_emul=elf32m32c
 			;;
diff --git a/ld/emulparams/elf32kvx.sh b/ld/emulparams/elf32kvx.sh
new file mode 100755
index 00000000000..b589c911614
--- /dev/null
+++ b/ld/emulparams/elf32kvx.sh
@@ -0,0 +1,32 @@
+#   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+#   Contributed by Kalray SA.
+
+#   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; see the file COPYING3. If not,
+#   see <http://www.gnu.org/licenses/>.  */
+
+ARCH=kvx
+MACHINE=
+SCRIPT_NAME=elf
+
+# bundle with 1 nop insn
+NOP=0x00f0037f
+
+TEMPLATE_NAME=elf
+EXTRA_EM_FILE=kvxelf
+
+OUTPUT_FORMAT="elf32-kvx"
+TEXT_START_ADDR=0x0
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+WRITABLE_RODATA=
+GENERATE_SHLIB_SCRIPT=yes
diff --git a/ld/emulparams/elf64kvx.sh b/ld/emulparams/elf64kvx.sh
new file mode 100644
index 00000000000..ad8ba0748bd
--- /dev/null
+++ b/ld/emulparams/elf64kvx.sh
@@ -0,0 +1,39 @@
+#   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+#   Contributed by Kalray SA.
+
+#   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; see the file COPYING3. If not,
+#   see <http://www.gnu.org/licenses/>.  */
+
+ARCH=kvx
+MACHINE=
+
+# bundle with 1 nop insn
+NOP=0x00f0037f
+
+SCRIPT_NAME=elf
+ELFSIZE=64
+OUTPUT_FORMAT="elf64-kvx"
+NO_REL_RELOCS=yes
+
+TEMPLATE_NAME=elf
+EXTRA_EM_FILE=kvxelf
+EMBEDDED=yes
+TEXT_START_ADDR=0x0
+
+# No support for .s* sections.
+NO_SMALL_DATA=yes
+
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+
+GENERATE_SHLIB_SCRIPT=yes
diff --git a/ld/emulparams/elf64kvx_linux.sh b/ld/emulparams/elf64kvx_linux.sh
new file mode 100644
index 00000000000..0bab70ab7e8
--- /dev/null
+++ b/ld/emulparams/elf64kvx_linux.sh
@@ -0,0 +1,41 @@
+#   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+#   Contributed by Kalray SA.
+
+#   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; see the file COPYING3. If not,
+#   see <http://www.gnu.org/licenses/>.  */
+
+ARCH=kvx
+MACHINE=
+
+# bundle with 1 nop insn
+NOP=0x00f0037f
+
+SCRIPT_NAME=elf
+ELFSIZE=64
+OUTPUT_FORMAT="elf64-kvx"
+NO_REL_RELOCS=yes
+
+TEMPLATE_NAME=elf
+
+# first user page at 64K.
+TEXT_START_ADDR=0x10000
+
+# No support for .s* sections.
+NO_SMALL_DATA=yes
+
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+
+GENERATE_SHLIB_SCRIPT=yes
+GENERATE_PIE_SCRIPT=yes
+
diff --git a/ld/emultempl/kvxelf.em b/ld/emultempl/kvxelf.em
new file mode 100644
index 00000000000..0b909eba999
--- /dev/null
+++ b/ld/emultempl/kvxelf.em
@@ -0,0 +1,310 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+#   Contributed by Kalray SA.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; see the file COPYING3. If not,
+# see <http://www.gnu.org/licenses/>.
+#
+
+# This file is sourced from elf32.em, and defines extra kvx-elf
+# specific routines.
+#
+fragment <<EOF
+
+#include "ldctor.h"
+#include "elf/kvx.h"
+#include "elfxx-kvx.h"
+
+
+static void
+elf${ELFSIZE}_kvx_before_allocation (void)
+{
+  if (bfd_link_pie (&link_info)) {
+          einfo (_("%F:%P: -pie not supported\n"));
+  }
+
+  /* Call the standard elf routine.  */
+  gld${EMULATION_NAME}_before_allocation ();
+}
+
+
+
+/* Fake input file for stubs.  */
+static lang_input_statement_type *stub_file;
+
+/* Whether we need to call gldarm_layout_sections_again.  */
+static int need_laying_out = 0;
+
+/* Maximum size of a group of input sections that can be handled by
+   one stub section.  A value of +/-1 indicates the bfd back-end
+   should use a suitable default size.  */
+static bfd_signed_vma group_size = -1;
+
+struct hook_stub_info
+{
+  lang_statement_list_type add;
+  asection *input_section;
+};
+
+/* Traverse the linker tree to find the spot where the stub goes.  */
+
+static bool
+hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
+{
+  lang_statement_union_type *l;
+  bool ret;
+
+  for (; (l = *lp) != NULL; lp = &l->header.next)
+    {
+      switch (l->header.type)
+	{
+	case lang_constructors_statement_enum:
+	  ret = hook_in_stub (info, &constructor_list.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_output_section_statement_enum:
+	  ret = hook_in_stub (info,
+                  &l->output_section_statement.children.head);
+
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_wild_statement_enum:
+	  ret = hook_in_stub (info, &l->wild_statement.children.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_group_statement_enum:
+	  ret = hook_in_stub (info, &l->group_statement.children.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_input_section_enum:
+	  if (l->input_section.section == info->input_section)
+            {
+	      /* We've found our section.  Insert the stub immediately
+		 after its associated input section.  */
+	      *(info->add.tail) = l->header.next;
+	      l->header.next = info->add.head;
+	      return true;
+	    }
+
+	  break;
+
+	case lang_data_statement_enum:
+	case lang_reloc_statement_enum:
+	case lang_object_symbols_statement_enum:
+	case lang_output_statement_enum:
+	case lang_target_statement_enum:
+	case lang_input_statement_enum:
+	case lang_assignment_statement_enum:
+	case lang_padding_statement_enum:
+	case lang_address_statement_enum:
+	case lang_fill_statement_enum:
+	  break;
+
+	default:
+	  FAIL ();
+	  break;
+	}
+    }
+  return false;
+}
+
+
+/* Call-back for elf${ELFSIZE}_kvx_size_stubs.  */
+
+/* Create a new stub section, and arrange for it to be linked
+   immediately after INPUT_SECTION.  */
+
+static asection *
+elf${ELFSIZE}_kvx_add_stub_section (const char *stub_sec_name,
+                                    asection *input_section)
+{
+  asection *stub_sec;
+  flagword flags;
+  asection *output_section;
+  lang_output_section_statement_type *os;
+  struct hook_stub_info info;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+	   | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
+  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
+						 stub_sec_name, flags);
+  if (stub_sec == NULL)
+    goto err_ret;
+
+  bfd_set_section_alignment (stub_sec, 2);
+
+  output_section = input_section->output_section;
+  os = lang_output_section_get (output_section);
+
+  info.input_section = input_section;
+  lang_list_init (&info.add);
+  lang_add_section (&info.add, stub_sec, NULL, NULL, os);
+
+  if (info.add.head == NULL)
+    goto err_ret;
+
+  if (hook_in_stub (&info, &os->children.head))
+    return stub_sec;
+
+ err_ret:
+  einfo ("%X%P: can not make stub section: %E\n");
+  return NULL;
+}
+
+/* Another call-back for elf${ELFSIZE}_kvx_size_stubs.  */
+
+static void
+gldkvx_layout_sections_again (void)
+{
+  /* If we have changed sizes of the stub sections, then we need
+     to recalculate all the section offsets.  This may mean we need to
+     add even more stubs.  */
+  ldelf_map_segments (true);
+  need_laying_out = -1;
+}
+
+static void
+build_section_lists (lang_statement_union_type *statement)
+{
+  if (statement->header.type == lang_input_section_enum)
+    {
+      asection *i = statement->input_section.section;
+
+      if (!((lang_input_statement_type *) i->owner->usrdata)->flags.just_syms
+	  && (i->flags & SEC_EXCLUDE) == 0
+	  && i->output_section != NULL
+	  && i->output_section->owner == link_info.output_bfd)
+	elf${ELFSIZE}_kvx_next_input_section (& link_info, i);
+    }
+}
+
+static void
+gld${EMULATION_NAME}_after_allocation (void)
+{
+  int ret;
+
+  /* bfd_elf32_discard_info just plays with debugging sections,
+     ie. doesn't affect any code, so we can delay resizing the
+     sections.  It's likely we'll resize everything in the process of
+     adding stubs.  */
+  ret = bfd_elf_discard_info (link_info.output_bfd, & link_info);
+  if (ret < 0)
+    {
+      einfo ("%X%P: .eh_frame/.stab edit: %E\n");
+      return;
+    }
+  else if (ret > 0)
+    need_laying_out = 1;
+
+  /* If generating a relocatable output file, then we don't
+     have to examine the relocs.  */
+  if (stub_file != NULL && !bfd_link_relocatable (&link_info))
+    {
+      ret = elf${ELFSIZE}_kvx_setup_section_lists (link_info.output_bfd,
+						       &link_info);
+      if (ret != 0)
+	{
+	  if (ret < 0)
+	    {
+	      einfo ("%X%P: could not compute sections lists for stub generation: %E\n");
+	      return;
+	    }
+
+	  lang_for_each_statement (build_section_lists);
+
+	  /* Call into the BFD backend to do the real work.  */
+	  if (! elf${ELFSIZE}_kvx_size_stubs (link_info.output_bfd,
+					  stub_file->the_bfd,
+					  & link_info,
+					  group_size,
+					  & elf${ELFSIZE}_kvx_add_stub_section,
+					  & gldkvx_layout_sections_again))
+	    {
+	      einfo ("%X%P: cannot size stub section: %E\n");
+	      return;
+	    }
+	}
+    }
+
+  if (need_laying_out != -1)
+    ldelf_map_segments (need_laying_out);
+}
+
+static void
+gld${EMULATION_NAME}_finish (void)
+{
+  if (!bfd_link_relocatable (&link_info))
+    {
+      /* Now build the linker stubs.  */
+      if (stub_file != NULL
+	  && stub_file->the_bfd->sections != NULL)
+	{
+	  if (! elf${ELFSIZE}_kvx_build_stubs (& link_info))
+	    einfo ("%X%P: can not build stubs: %E\n");
+	}
+    }
+
+  finish_default ();
+}
+
+/* This is a convenient point to tell BFD about target specific flags.
+   After the output has been created, but before inputs are read.  */
+static void
+kvx_elf_create_output_section_statements (void)
+{
+  if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+        && elf_object_id (link_info.output_bfd) == KVX_ELF_DATA))
+    return;
+
+  stub_file = lang_add_input_file ("linker stubs",
+				   lang_input_file_is_fake_enum,
+				   NULL);
+  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
+  if (stub_file->the_bfd == NULL
+      || ! bfd_set_arch_mach (stub_file->the_bfd,
+			      bfd_get_arch (link_info.output_bfd),
+			      bfd_get_mach (link_info.output_bfd)))
+    {
+      einfo ("%X%P: can not create BFD %E\n");
+      return;
+    }
+
+  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
+  ldlang_add_file (stub_file);
+
+  if (!kvx_elf${ELFSIZE}_init_stub_bfd (&link_info, stub_file->the_bfd))
+    einfo ("%F%P: can not init BFD: %E\n");
+}
+
+
+#define lang_for_each_input_file kvx_lang_for_each_input_file
+
+EOF
+
+LDEMUL_BEFORE_ALLOCATION=elf${ELFSIZE}_kvx_before_allocation
+LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=kvx_elf_create_output_section_statements
+
+# Call the extra arm-elf function
+LDEMUL_FINISH=gld${EMULATION_NAME}_finish
diff --git a/ld/po/BLD-POTFILES.in b/ld/po/BLD-POTFILES.in
index 1fb352a1dfa..54de42b6511 100644
--- a/ld/po/BLD-POTFILES.in
+++ b/ld/po/BLD-POTFILES.in
@@ -115,6 +115,7 @@ eelf32ft32.c
 eelf32ip2k.c
 eelf32iq10.c
 eelf32iq2000.c
+eelf32kvx.c
 eelf32l4300.c
 eelf32lm32.c
 eelf32lm32fd.c
@@ -185,6 +186,8 @@ eelf64briscv_lp64f.c
 eelf64btsmip.c
 eelf64btsmip_fbsd.c
 eelf64hppa.c
+eelf64kvx.c
+eelf64kvx_linux.c
 eelf64loongarch.c
 eelf64lppc.c
 eelf64lppc_fbsd.c
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index cf010e5b0e5..bcb69ebfc49 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -515,6 +515,7 @@ run_ld_link_tests {
 }
 
 if { [istarget *-*-linux*]
+     || [istarget kvx-*-*]
      || [istarget *-*-nacl*]
      || [istarget *-*-gnu*] } {
     run_ld_link_tests {
diff --git a/ld/testsuite/ld-kvx/farcall-back.d b/ld/testsuite/ld-kvx/farcall-back.d
new file mode 100644
index 00000000000..c17dda71834
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-back.d
@@ -0,0 +1,79 @@
+#name: kvx-farcall-back
+#source: farcall-back.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x80001000
+#objdump: -dr
+
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+    .*:	.. .. .. ..                                     	call .* <__bar1_veneer>;;
+
+    .*:	.. .. .. ..                                     	goto .* <__bar1_veneer>;;
+
+    .*:	.. .. .. ..                                     	call .* <__bar2_veneer>;;
+
+    .*:	.. .. .. ..                                     	goto .* <__bar2_veneer>;;
+
+    .*:	.. .. .. ..                                     	call .* <__bar3_veneer>;;
+
+    .*:	.. .. .. ..                                     	goto .* <__bar3_veneer>;;
+
+    .*:	00 00 d0 0f                                     	ret;;
+
+	...
+
+.* <_back>:
+    .*:	00 00 d0 0f                                     	ret;;
+
+.* <__bar3_veneer>:
+    .*:	00 .. 40 e0 0c 00 20 00                         	make \$r16 = .* \(0x.*\);;
+
+    .*:	10 00 d8 0f                                     	igoto \$r16;;
+
+.* <__bar2_veneer>:
+    .*:	00 .. 40 e0 08 00 20 00                         	make \$r16 = .* \(0x.*\);;
+
+    .*:	10 00 d8 0f                                     	igoto \$r16;;
+
+.* <__bar1_veneer>:
+    .*:	00 .. 40 e0 04 00 20 00                         	make \$r16 = .* \(0x.*\);;
+
+    .*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .foo:
+
+.* <bar1>:
+.*:	00 00 d0 0f                                     	ret;;
+
+.*:	.. .. .. ..                                     	goto .* <___start_veneer>;;
+
+	...
+
+.* <bar2>:
+.*:	00 00 d0 0f                                     	ret;;
+
+.*:	.. .. .. ..                                     	goto .* <___start_veneer>;;
+
+	...
+
+.* <bar3>:
+.*:	00 00 d0 0f                                     	ret;;
+
+.*:	.. .. .. ..                                     	goto .* <___back_veneer>;;
+
+
+.* <___start_veneer>:
+.*:	00 .. 40 e0 04 00 00 00                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+.* <___back_veneer>:
+.*:	00 .. 40 e0 08 00 00 00                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
diff --git a/ld/testsuite/ld-kvx/farcall-back.s b/ld/testsuite/ld-kvx/farcall-back.s
new file mode 100644
index 00000000000..582d39d3d82
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-back.s
@@ -0,0 +1,54 @@
+	.global _start
+	.global _back
+	.global bar1
+	.global bar2
+	.global bar3
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+	.type _start, @function
+_start:
+	call	bar1
+	;; 
+	goto	bar1
+	;; 
+	call	bar2
+	;; 
+	goto	bar2
+	;; 
+	call	bar3
+	;; 
+	goto	bar3
+	;; 
+	ret
+	;; 
+	.space	0x1000
+	.type _back, @function
+_back:	ret
+	;;
+
+# We will place the section .foo at 0x80001000.
+
+	.section .foo, "xa"
+	.type bar1, @function
+bar1:
+	ret
+	;; 
+	goto	_start
+	;; 
+	.space 0x1000
+	.type bar2, @function
+bar2:
+	ret
+	;; 
+	goto	_start
+	;; 
+	.space 0x1000
+	.type bar3, @function
+bar3:
+	ret
+	;; 
+	goto	_back
+	;; 
diff --git a/ld/testsuite/ld-kvx/farcall-call-defsym.d b/ld/testsuite/ld-kvx/farcall-call-defsym.d
new file mode 100644
index 00000000000..71dcebcc555
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-defsym.d
@@ -0,0 +1,14 @@
+#name: kvx-farcall-call-defsym
+#source: farcall-call-defsym.s
+#as:
+#ld: -Ttext 0x1000 --defsym=bar=0x8001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+    1000:	00 00 00 1a                                     	call 8001000 <bar>;;
+
+    1004:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call-defsym.s b/ld/testsuite/ld-kvx/farcall-call-defsym.s
new file mode 100644
index 00000000000..2072b53960a
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-defsym.s
@@ -0,0 +1,12 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	call bar
+	;;
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-call-none-function.d b/ld/testsuite/ld-kvx/farcall-call-none-function.d
new file mode 100644
index 00000000000..3ef4131e327
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-none-function.d
@@ -0,0 +1,24 @@
+#name: kvx-farcall-call-none-function
+#source: farcall-call-none-function.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+.*:	.. .. .. ..                                     	call .* <__bar_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <__bar_veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call-none-function.s b/ld/testsuite/ld-kvx/farcall-call-none-function.s
new file mode 100644
index 00000000000..85eeca5616f
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-none-function.s
@@ -0,0 +1,19 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	call bar
+	;;
+	ret
+	;;
+	
+# We will place the section .foo at 0x10001000.
+
+	.section .foo, "xa"
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-call-plt-32bits.d b/ld/testsuite/ld-kvx/farcall-call-plt-32bits.d
new file mode 100644
index 00000000000..a097e28ccfc
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-plt-32bits.d
@@ -0,0 +1,31 @@
+
+tmpdir/dump:     file format elf32-kvx
+
+
+Disassembly of section .plt:
+
+.* <foo@plt-0x20>:
+	...
+
+.* <foo@plt>:
+ .*:	10 00 c4 0f                                     	get \$r16 = \$pc;;
+
+ .*:	.. .. 40 b0 .. .. .. 18                         	lwz \$r16 = [0-9]* \(0x[0-9a-f]*\)\[\$r16\];;
+
+ .*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	.. .. 00 18                                     	call .* <__foo_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+
+.* <__foo_veneer>:
+.*:	.. .. 40 e0 00 00 00 00                         	make \$r16 = .* \(0x[0-9a-f]*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call-plt.d b/ld/testsuite/ld-kvx/farcall-call-plt.d
new file mode 100644
index 00000000000..ab431b0e3c4
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-plt.d
@@ -0,0 +1,34 @@
+#name: kvx-farcall-call-plt
+#source: farcall-call-plt.s
+#as:
+#ld: -shared
+#objdump: -dr
+#...
+
+Disassembly of section .plt:
+
+.* <.plt>:
+	...
+
+.* <foo@plt>:
+.*:	10 00 c4 0f                                     	get \$r16 = \$pc;;
+
+.*:	.. .. 40 .. .. .. .. 18                         	l[wzd]* \$r16 = [0-9]* \(0x[0-9a-f]*\)\[\$r16\];;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	.. .. 00 18                                     	call .* <__foo_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+
+.* <__foo_veneer>:
+.*:	.. .. 40 e0 00 00 00 00                         	make \$r16 = .* \(0x[0-9a-f]*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call-plt.s b/ld/testsuite/ld-kvx/farcall-call-plt.s
new file mode 100644
index 00000000000..e1b1bbc6bea
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-plt.s
@@ -0,0 +1,14 @@
+	.global _start
+	.global foo
+	.type foo, @function
+	.text
+
+_start:
+	# ((1 << 26) - 1) << 2
+	# PCREL27 relocation out of range to plt stub,
+	# we need long branch veneer.
+	.skip 268435452, 0
+	call foo
+	;;
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-call-section.d b/ld/testsuite/ld-kvx/farcall-call-section.d
new file mode 100644
index 00000000000..86f3f035caf
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-section.d
@@ -0,0 +1,34 @@
+#name: kvx-farcall-call-section
+#source: farcall-call-section.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+.*:	.. .. .. ..                                     	call .* <___veneer>;;
+
+.*:	.. .. .. ..                                     	call .* <___veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <___veneer>:
+.*:	.. 00 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+.* <___veneer>:
+.*:	.. 01 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <bar2>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call-section.s b/ld/testsuite/ld-kvx/farcall-call-section.s
new file mode 100644
index 00000000000..3b22fc66a8a
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call-section.s
@@ -0,0 +1,25 @@
+	.global _start
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	call bar
+	;; 
+	call bar2
+	;; 
+	ret
+	;; 
+
+# We will place the section .foo at 0x20001000.
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;; 
+	.type bar2, @function
+bar2:
+	ret
+	;; 
diff --git a/ld/testsuite/ld-kvx/farcall-call.d b/ld/testsuite/ld-kvx/farcall-call.d
new file mode 100644
index 00000000000..6db1f168f74
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call.d
@@ -0,0 +1,25 @@
+#name: kvx-farcall-call
+#source: farcall-call.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+
+.* <_start>:
+.*:	.. .. .. 18                                     	call .* <__bar_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <__bar_veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-call.s b/ld/testsuite/ld-kvx/farcall-call.s
new file mode 100644
index 00000000000..7319ae40f94
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-call.s
@@ -0,0 +1,20 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	call bar
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x20001000.
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-goto-defsym.d b/ld/testsuite/ld-kvx/farcall-goto-defsym.d
new file mode 100644
index 00000000000..27ba7be1eaf
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-defsym.d
@@ -0,0 +1,14 @@
+#name: kvx-farcall-goto-defsym
+#source: farcall-goto-defsym.s
+#as:
+#ld: -Ttext 0x1000 --defsym=bar=0x8001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+    1000:	00 00 00 12                                     	goto 8001000 <bar>;;
+
+    1004:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto-defsym.s b/ld/testsuite/ld-kvx/farcall-goto-defsym.s
new file mode 100644
index 00000000000..f2e1da61d48
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-defsym.s
@@ -0,0 +1,12 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	goto bar
+	;; 
+	ret
+	;; 
diff --git a/ld/testsuite/ld-kvx/farcall-goto-gsym.d b/ld/testsuite/ld-kvx/farcall-goto-gsym.d
new file mode 100644
index 00000000000..9874d415daa
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-gsym.d
@@ -0,0 +1,5 @@
+#name: kvx-farcall-goto-gsym
+#source: farcall-goto-gsym.s
+#as:
+#ld: -Ttext 0x1000
+#error: .*\(.text\+0x0\): relocation truncated to fit: R_KVX_PCREL27 against symbol `bar_gsym'.*
diff --git a/ld/testsuite/ld-kvx/farcall-goto-gsym.s b/ld/testsuite/ld-kvx/farcall-goto-gsym.s
new file mode 100644
index 00000000000..2cb7b19b6f0
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-gsym.s
@@ -0,0 +1,20 @@
+	.global _start
+	.global bar_gsym
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+# for long jump (goto) to global symbol, we shouldn't insert veneer
+# as the veneer will clobber r16/r17 which is caller saved, gcc only
+# reserve them for function call relocation (call).
+	goto bar_gsym
+	;;
+	# ((1 << 26) - 1) << 2
+	.skip 268435452, 0
+bar_gsym:
+	nop
+	;;
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-goto-none-function.d b/ld/testsuite/ld-kvx/farcall-goto-none-function.d
new file mode 100644
index 00000000000..88b7a277d41
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-none-function.d
@@ -0,0 +1,26 @@
+#name: kvx-farcall-goto-none-function
+#source: farcall-goto-none-function.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+
+.* <_start>:
+.*:	.. .. .. ..                                     	goto .* <__bar_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <__bar_veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto-none-function.s b/ld/testsuite/ld-kvx/farcall-goto-none-function.s
new file mode 100644
index 00000000000..1223bc315b1
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-none-function.s
@@ -0,0 +1,19 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	goto bar
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x20001000.
+
+	.section .foo, "xa"
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-goto-plt-32bits.d b/ld/testsuite/ld-kvx/farcall-goto-plt-32bits.d
new file mode 100644
index 00000000000..04b43802fdd
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-plt-32bits.d
@@ -0,0 +1,31 @@
+
+tmpdir/dump:     file format elf32-kvx
+
+
+Disassembly of section .plt:
+
+.* <.plt>:
+	...
+
+.* <foo@plt>:
+.*:	10 00 c4 0f                                     	get \$r16 = \$pc;;
+
+.*:	.. .. 40 .. .. .. .. ..                         	l[wzd]* \$r16 = [0-9]* \(0x[0-9a-b]*\)\[\$r16\];;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	.. .. .. 10                                     	goto .* <__foo_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+
+.* <__foo_veneer>:
+.*:	.. .. 40 e0 00 00 00 00                         	make \$r16 = [0-9]* \(0x[0-9a-b]*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto-plt.d b/ld/testsuite/ld-kvx/farcall-goto-plt.d
new file mode 100644
index 00000000000..e1e20e6ab06
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-plt.d
@@ -0,0 +1,34 @@
+#name: kvx-farcall-goto-plt
+#source: farcall-goto-plt.s
+#as:
+#ld: -shared
+#objdump: -dr
+#...
+
+Disassembly of section .plt:
+
+.* <.plt>:
+	...
+
+.* <foo@plt>:
+.*:	10 00 c4 0f                                     	get \$r16 = \$pc;;
+
+.*:	.. .. 40 .. .. .. .. ..                         	l[wzd]* \$r16 = [0-9]* \(0x[0-9a-b]*\)\[\$r16\];;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .text:
+
+.* <_start>:
+	...
+.*:	.. .. .. 10                                     	goto .* <__foo_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+
+.* <__foo_veneer>:
+.*:	.. .. 40 e0 00 00 00 00                         	make \$r16 = [0-9]* \(0x[0-9a-b]*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto-plt.s b/ld/testsuite/ld-kvx/farcall-goto-plt.s
new file mode 100644
index 00000000000..f912d9f2cdd
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-plt.s
@@ -0,0 +1,13 @@
+	.global _start
+	.global foo
+	.type foo, @function
+	.text
+_start:
+	# ((1 << 26) - 1) << 2
+	# PCREL27 relocation out of range to plt stub,
+	# we need long branch veneer.
+	.skip 268435452, 0
+	goto foo
+	;;
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-goto-section.d b/ld/testsuite/ld-kvx/farcall-goto-section.d
new file mode 100644
index 00000000000..059979586b0
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-section.d
@@ -0,0 +1,36 @@
+#name: kvx-farcall-goto-section
+#source: farcall-goto-section.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+.*:	.. .. .. ..                                     	goto .* <___veneer>;;
+
+.*:	.. .. .. ..                                     	goto .* <___veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <___veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+.* <___veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
+
+.* <bar2>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto-section.s b/ld/testsuite/ld-kvx/farcall-goto-section.s
new file mode 100644
index 00000000000..d6287d1d57e
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto-section.s
@@ -0,0 +1,25 @@
+.global _start
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	goto bar
+	;;
+	goto bar2
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x20001000.
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;;
+	.type bar2, @function
+bar2:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/farcall-goto.d b/ld/testsuite/ld-kvx/farcall-goto.d
new file mode 100644
index 00000000000..7e34eeb5cb8
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto.d
@@ -0,0 +1,25 @@
+#name: kvx-farcall-goto
+#source: farcall-goto.s
+#as:
+#ld: -Ttext 0x1000 --section-start .foo=0x20001000
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+.*:	.. .. .. ..                                     	goto .* <__bar_veneer>;;
+
+.*:	00 00 d0 0f                                     	ret;;
+
+.* <__bar_veneer>:
+.*:	.. .. 40 e0 .. .. .. ..                         	make \$r16 = .* \(0x.*\);;
+
+.*:	10 00 d8 0f                                     	igoto \$r16;;
+
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/farcall-goto.s b/ld/testsuite/ld-kvx/farcall-goto.s
new file mode 100644
index 00000000000..114bc56bc45
--- /dev/null
+++ b/ld/testsuite/ld-kvx/farcall-goto.s
@@ -0,0 +1,20 @@
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x1000.
+
+	.text
+
+_start:
+	goto bar
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x20001000.
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/kvx-elf.exp b/ld/testsuite/ld-kvx/kvx-elf.exp
new file mode 100644
index 00000000000..b5a0833078a
--- /dev/null
+++ b/ld/testsuite/ld-kvx/kvx-elf.exp
@@ -0,0 +1,70 @@
+# Expect script for various KVX ELF tests.
+# Copyright (C) 2009-2016 Free Software Foundation, Inc.
+#
+# Copyright (C) 2019 Kalray
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# Exclude non-kvx-ELF targets.
+if { ![istarget "kvx-*-*"] } {
+    return
+}
+
+# List contains test-items with 3 items followed by 2 lists:
+# 0:name 1:ld early options 2:ld late options 3:assembler options
+# 4:filenames of assembler files 5: action and options. 6: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+# 64bits tests
+run_dump_test "limit-call"
+run_dump_test "limit-goto"
+run_dump_test "farcall-back"
+run_dump_test "farcall-goto-defsym"
+run_dump_test "farcall-call-defsym"
+run_dump_test "farcall-goto-gsym"
+run_dump_test "farcall-goto-plt"
+run_dump_test "farcall-call-plt"
+run_dump_test "farcall-call"
+run_dump_test "farcall-goto"
+run_dump_test "farcall-goto-none-function"
+run_dump_test "farcall-call-none-function"
+run_dump_test "farcall-goto-section"
+run_dump_test "farcall-call-section"
+run_dump_test "pcrel-reloc"
+
+## 32bits tests
+set extra_32bits [list [list as -m32] [list ld -melf32kvx]]
+run_dump_test "limit-call" $extra_32bits
+run_dump_test "limit-goto" $extra_32bits
+run_dump_test "farcall-back" $extra_32bits
+run_dump_test "farcall-goto-defsym" $extra_32bits
+run_dump_test "farcall-call-defsym" $extra_32bits
+run_dump_test "farcall-goto-gsym" $extra_32bits
+run_dump_test "farcall-goto-plt" $extra_32bits
+run_dump_test "farcall-call-plt" $extra_32bits
+run_dump_test "farcall-call" $extra_32bits
+run_dump_test "farcall-goto" $extra_32bits
+run_dump_test "farcall-goto-none-function" $extra_32bits
+run_dump_test "farcall-call-none-function" $extra_32bits
+run_dump_test "farcall-goto-section" $extra_32bits
+run_dump_test "farcall-call-section" $extra_32bits
+run_dump_test "pcrel-reloc" [list [list as -m32] [list ld -melf32kvx] [list dump pcrel-reloc-32bits.d]]
diff --git a/ld/testsuite/ld-kvx/kvx.ld b/ld/testsuite/ld-kvx/kvx.ld
new file mode 100644
index 00000000000..b1f3c050455
--- /dev/null
+++ b/ld/testsuite/ld-kvx/kvx.ld
@@ -0,0 +1,18 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(kv3-1:64)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x8000); . = 0x8000;
+  .text           :
+  {
+    *(.before)
+    *(.text)
+    *(.after)
+  } =0
+  . = 0x9000;
+  .got            : { *(.got) *(.got.plt)}
+  . = 0x12340000;
+  .far : { *(.far) }
+}
diff --git a/ld/testsuite/ld-kvx/limit-call.d b/ld/testsuite/ld-kvx/limit-call.d
new file mode 100644
index 00000000000..a9b6c728a34
--- /dev/null
+++ b/ld/testsuite/ld-kvx/limit-call.d
@@ -0,0 +1,20 @@
+#name: kvx-limit-call
+#source: limit-call.s
+#as:
+#ld: -Ttext 0x0000 --section-start .foo=0x0FFFFFFC
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+   0:	ff ff ff 1b                                     	call ffffffc <bar>;;
+
+   4:	00 00 d0 0f                                     	ret;;
+
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/limit-call.s b/ld/testsuite/ld-kvx/limit-call.s
new file mode 100644
index 00000000000..e5cff120a38
--- /dev/null
+++ b/ld/testsuite/ld-kvx/limit-call.s
@@ -0,0 +1,22 @@
+# Test maximum encoding range of call
+
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x0000.
+
+	.text
+
+_start:
+	call bar
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x10000000
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/limit-goto.d b/ld/testsuite/ld-kvx/limit-goto.d
new file mode 100644
index 00000000000..36c4386ed62
--- /dev/null
+++ b/ld/testsuite/ld-kvx/limit-goto.d
@@ -0,0 +1,20 @@
+#name: kvx-limit-goto
+#source: limit-goto.s
+#as:
+#ld: -Ttext 0x0 --section-start .foo=0x0FFFFFFC
+#objdump: -dr
+#...
+
+Disassembly of section .text:
+
+.* <_start>:
+   0:	ff ff ff 13                                     	goto ffffffc <bar>;;
+
+   4:	00 00 d0 0f                                     	ret;;
+
+
+Disassembly of section .foo:
+
+.* <bar>:
+.*:	00 00 d0 0f                                     	ret;;
+
diff --git a/ld/testsuite/ld-kvx/limit-goto.s b/ld/testsuite/ld-kvx/limit-goto.s
new file mode 100644
index 00000000000..f90211444ad
--- /dev/null
+++ b/ld/testsuite/ld-kvx/limit-goto.s
@@ -0,0 +1,22 @@
+# Test maximum encoding range of call
+
+	.global _start
+	.global bar
+
+# We will place the section .text at 0x0000.
+
+	.text
+
+_start:
+	goto bar
+	;;
+	ret
+	;;
+
+# We will place the section .foo at 0x10000000
+
+	.section .foo, "xa"
+	.type bar, @function
+bar:
+	ret
+	;;
diff --git a/ld/testsuite/ld-kvx/pcrel-reloc-32bits.d b/ld/testsuite/ld-kvx/pcrel-reloc-32bits.d
new file mode 100644
index 00000000000..3ca9eb958f5
--- /dev/null
+++ b/ld/testsuite/ld-kvx/pcrel-reloc-32bits.d
@@ -0,0 +1,8 @@
+.*:     file format elf32-kvx
+
+
+Disassembly of section .text:
+
+.* <_start>:
+.*:	00 00 d0 8f                                     	ret
+.*:	c0 cd 04 f0 04 00 00 00                         	pcrel \$r1 = 4919 \(0x1337\);;
diff --git a/ld/testsuite/ld-kvx/pcrel-reloc.d b/ld/testsuite/ld-kvx/pcrel-reloc.d
new file mode 100644
index 00000000000..1931d9ef666
--- /dev/null
+++ b/ld/testsuite/ld-kvx/pcrel-reloc.d
@@ -0,0 +1,14 @@
+#name: pcrel-reloc
+#source: pcrel-reloc.s
+#as:
+#ld: -Ttext 0x0 --defsym foo=0x1337
+#objdump: -dr
+
+.*:     file format elf64-kvx
+
+
+Disassembly of section .text:
+
+0000000000000000 <_start>:
+   0:	00 00 d0 8f                                     	ret
+   4:	c0 cd 04 f0 04 00 00 80 00 00 00 00             	pcrel \$r1 = 4919 \(0x1337\);;
diff --git a/ld/testsuite/ld-kvx/pcrel-reloc.s b/ld/testsuite/ld-kvx/pcrel-reloc.s
new file mode 100644
index 00000000000..825a38189a4
--- /dev/null
+++ b/ld/testsuite/ld-kvx/pcrel-reloc.s
@@ -0,0 +1,10 @@
+.text
+.global _start
+.weak foo
+.hidden foo
+
+.type _start, @function
+_start:
+	pcrel $r1 = @pcrel(foo)
+	ret
+	;;
