public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
* [binutils-gdb] kvx: New port.
@ 2023-08-16 13:23 Nick Clifton
  0 siblings, 0 replies; only message in thread
From: Nick Clifton @ 2023-08-16 13:23 UTC (permalink / raw)
  To: bfd-cvs, gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6e712424f5cb1f01acf41c21f8721ee028c2a20c

commit 6e712424f5cb1f01acf41c21f8721ee028c2a20c
Author: Paul Iannetta <piannetta@kalrayinc.com>
Date:   Wed Aug 16 14:22:28 2023 +0100

    kvx: New port.

Diff:
---
 bfd/Makefile.am                                  |     21 +
 bfd/Makefile.in                                  |     26 +
 bfd/archures.c                                   |     13 +
 bfd/bfd-in2.h                                    |    111 +
 bfd/config.bfd                                   |     16 +
 bfd/configure                                    |      3 +
 bfd/configure.ac                                 |      3 +
 bfd/cpu-kvx.c                                    |    124 +
 bfd/elf-bfd.h                                    |      1 +
 bfd/elfnn-kvx.c                                  |   4805 +
 bfd/elfxx-kvx-relocs.h                           |   1105 +
 bfd/elfxx-kvx.c                                  |    218 +
 bfd/elfxx-kvx.h                                  |     71 +
 bfd/libbfd.h                                     |     85 +
 bfd/po/BLD-POTFILES.in                           |      2 +
 bfd/po/SRC-POTFILES.in                           |      2 +
 bfd/reloc.c                                      |    186 +-
 bfd/targets.c                                    |      8 +
 binutils/readelf.c                               |     26 +
 binutils/testsuite/binutils-all/nm.exp           |      1 +
 binutils/testsuite/binutils-all/objcopy.exp      |      1 +
 binutils/testsuite/binutils-all/objdump.exp      |      2 +
 binutils/testsuite/lib/binutils-common.exp       |      7 +
 config.guess                                     |      9 +
 config.sub                                       |     16 +-
 configure                                        |     12 +
 configure.ac                                     |     12 +
 gas/Makefile.am                                  |      6 +-
 gas/Makefile.in                                  |     18 +-
 gas/NEWS                                         |      2 +
 gas/config/kvx-parse.c                           |   1012 +
 gas/config/kvx-parse.h                           |  33815 ++++++
 gas/config/tc-kvx.c                              |   2676 +
 gas/config/tc-kvx.h                              |    317 +
 gas/configure                                    |     11 +
 gas/configure.ac                                 |      8 +
 gas/configure.tgt                                |      6 +-
 gas/doc/all.texi                                 |      1 +
 gas/doc/as.texi                                  |      7 +
 gas/doc/c-kvx.texi                               |    147 +
 gas/doc/local.mk                                 |      1 +
 gas/testsuite/gas/all/org-1.d                    |      1 +
 gas/testsuite/gas/elf/bad-bss.d                  |      2 +-
 gas/testsuite/gas/elf/bss.d                      |      2 +-
 gas/testsuite/gas/elf/elf.exp                    |      1 +
 gas/testsuite/gas/kvx/kv3-1-insns-32.d           |   2297 +
 gas/testsuite/gas/kvx/kv3-1-insns-32.s           |   2307 +
 gas/testsuite/gas/kvx/kv3-1-insns-64.d           |   2297 +
 gas/testsuite/gas/kvx/kv3-1-insns-64.s           |   2307 +
 gas/testsuite/gas/kvx/kv3-2-insns-32.d           |   2416 +
 gas/testsuite/gas/kvx/kv3-2-insns-32.s           |   2425 +
 gas/testsuite/gas/kvx/kv3-2-insns-64.d           |   2415 +
 gas/testsuite/gas/kvx/kv3-2-insns-64.s           |   2425 +
 gas/testsuite/gas/kvx/kv4-1-insns-32.d           |   2408 +
 gas/testsuite/gas/kvx/kv4-1-insns-32.s           |   2417 +
 gas/testsuite/gas/kvx/kv4-1-insns-64.d           |   2407 +
 gas/testsuite/gas/kvx/kv4-1-insns-64.s           |   2417 +
 gas/testsuite/gas/kvx/kvx.exp                    |     23 +
 gas/testsuite/gas/kvx/nop-align.d                |     31 +
 gas/testsuite/gas/kvx/nop-align.s                |     35 +
 gas/testsuite/gas/lns/lns-common-1-kvx.s         |     33 +
 gas/testsuite/gas/lns/lns.exp                    |      2 +
 include/dis-asm.h                                |      1 +
 include/elf/kvx.h                                |    115 +
 include/elf/kvx_elfids.h                         |     81 +
 include/opcode/kvx.h                             |   3159 +
 ld/Makefile.am                                   |      6 +
 ld/Makefile.in                                   |      9 +
 ld/NEWS                                          |      2 +
 ld/configure.tgt                                 |      5 +
 ld/emulparams/elf32kvx.sh                        |     32 +
 ld/emulparams/elf64kvx.sh                        |     39 +
 ld/emulparams/elf64kvx_linux.sh                  |     41 +
 ld/emultempl/kvxelf.em                           |    316 +
 ld/po/BLD-POTFILES.in                            |      3 +
 ld/testsuite/ld-ctf/nonrepresentable.d           |      2 +-
 ld/testsuite/ld-elf/elf.exp                      |      1 +
 ld/testsuite/ld-elf/shared.exp                   |      3 +-
 ld/testsuite/ld-ifunc/ifunc.exp                  |      1 +
 ld/testsuite/ld-kvx/farcall-back.d               |     79 +
 ld/testsuite/ld-kvx/farcall-back.s               |     54 +
 ld/testsuite/ld-kvx/farcall-call-defsym.d        |     14 +
 ld/testsuite/ld-kvx/farcall-call-defsym.s        |     12 +
 ld/testsuite/ld-kvx/farcall-call-none-function.d |     24 +
 ld/testsuite/ld-kvx/farcall-call-none-function.s |     19 +
 ld/testsuite/ld-kvx/farcall-call-plt-32bits.d    |     31 +
 ld/testsuite/ld-kvx/farcall-call-plt.d           |     34 +
 ld/testsuite/ld-kvx/farcall-call-plt.s           |     14 +
 ld/testsuite/ld-kvx/farcall-call-section.d       |     34 +
 ld/testsuite/ld-kvx/farcall-call-section.s       |     25 +
 ld/testsuite/ld-kvx/farcall-call.d               |     25 +
 ld/testsuite/ld-kvx/farcall-call.s               |     20 +
 ld/testsuite/ld-kvx/farcall-goto-defsym.d        |     14 +
 ld/testsuite/ld-kvx/farcall-goto-defsym.s        |     12 +
 ld/testsuite/ld-kvx/farcall-goto-gsym.d          |      5 +
 ld/testsuite/ld-kvx/farcall-goto-gsym.s          |     20 +
 ld/testsuite/ld-kvx/farcall-goto-none-function.d |     26 +
 ld/testsuite/ld-kvx/farcall-goto-none-function.s |     19 +
 ld/testsuite/ld-kvx/farcall-goto-plt-32bits.d    |     31 +
 ld/testsuite/ld-kvx/farcall-goto-plt.d           |     34 +
 ld/testsuite/ld-kvx/farcall-goto-plt.s           |     13 +
 ld/testsuite/ld-kvx/farcall-goto-section.d       |     36 +
 ld/testsuite/ld-kvx/farcall-goto-section.s       |     25 +
 ld/testsuite/ld-kvx/farcall-goto.d               |     25 +
 ld/testsuite/ld-kvx/farcall-goto.s               |     20 +
 ld/testsuite/ld-kvx/kvx-elf.exp                  |     71 +
 ld/testsuite/ld-kvx/kvx.ld                       |     18 +
 ld/testsuite/ld-kvx/limit-call.d                 |     20 +
 ld/testsuite/ld-kvx/limit-call.s                 |     22 +
 ld/testsuite/ld-kvx/limit-goto.d                 |     20 +
 ld/testsuite/ld-kvx/limit-goto.s                 |     22 +
 ld/testsuite/ld-kvx/pcrel-reloc-32bits.d         |      8 +
 ld/testsuite/ld-kvx/pcrel-reloc.d                |     14 +
 ld/testsuite/ld-kvx/pcrel-reloc.s                |     10 +
 ld/testsuite/ld-scripts/fill.d                   |      2 +
 opcodes/Makefile.am                              |      2 +
 opcodes/Makefile.in                              |      4 +
 opcodes/configure                                |      1 +
 opcodes/configure.ac                             |      1 +
 opcodes/disassemble.c                            |      9 +
 opcodes/disassemble.h                            |      1 +
 opcodes/kvx-dis.c                                |   1619 +
 opcodes/kvx-dis.h                                |     65 +
 opcodes/kvx-opc.c                                | 111104 ++++++++++++++++++++
 opcodes/po/POTFILES.in                           |      2 +
 125 files changed, 191062 insertions(+), 15 deletions(-)

diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 5c5fdefd3b8..464d6dd692f 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -122,6 +122,7 @@ ALL_MACHINES = \
 	cpu-ip2k.lo \
 	cpu-iq2000.lo \
 	cpu-lm32.lo \
+	cpu-kvx.lo \
 	cpu-loongarch.lo \
 	cpu-m10200.lo \
 	cpu-m10300.lo \
@@ -201,6 +202,7 @@ ALL_MACHINES_CFILES = \
 	cpu-hppa.c \
 	cpu-i386.c \
 	cpu-iamcu.c \
+	cpu-kvx.c \
 	cpu-ia64.c \
 	cpu-ip2k.c \
 	cpu-iq2000.c \
@@ -317,6 +319,8 @@ BFD32_BACKENDS = \
 	elfxx-x86.lo \
 	elf32-ip2k.lo \
 	elf32-iq2000.lo \
+	elf32-kvx.lo \
+	elfxx-kvx.lo \
 	elf32-lm32.lo \
 	elf32-m32c.lo \
 	elf32-m32r.lo \
@@ -452,6 +456,7 @@ BFD32_BACKENDS_CFILES = \
 	elfxx-x86.c \
 	elf32-ip2k.c \
 	elf32-iq2000.c \
+	elfxx-kvx.c \
 	elf32-lm32.c \
 	elf32-m32c.c \
 	elf32-m32r.c \
@@ -556,6 +561,8 @@ BFD64_BACKENDS = \
 	elf64-ia64.lo \
 	elf64-ia64-vms.lo \
 	elfxx-ia64.lo \
+	elfxx-kvx.lo \
+	elf64-kvx.lo \
 	elf32-loongarch.lo \
 	elf64-loongarch.lo \
 	elfxx-loongarch.lo \
@@ -618,6 +625,7 @@ BFD64_BACKENDS_CFILES = \
 	elfn32-mips.c \
 	elfxx-aarch64.c \
 	elfxx-ia64.c \
+	elfxx-kvx.c \
 	elfxx-loongarch.c \
 	elfxx-mips.c \
 	elfxx-riscv.c \
@@ -681,6 +689,7 @@ SOURCE_CFILES = \
 
 BUILD_CFILES = \
 	elf32-aarch64.c elf64-aarch64.c \
+	elf32-kvx.c elf64-kvx.c \
 	elf32-ia64.c elf64-ia64.c \
 	elf32-loongarch.c elf64-loongarch.c \
 	elf32-riscv.c elf64-riscv.c \
@@ -850,6 +859,18 @@ elf64-ia64.c : elfnn-ia64.c
 	$(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
 
+elf32-kvx.c : elfnn-kvx.c
+	rm -f elf32-kvx.c
+	echo "#line 1 \"$(srcdir)/elfnn-kvx.c\"" > elf32-kvx.new
+	sed -e s/NN/32/g < $(srcdir)/elfnn-kvx.c >> elf32-kvx.new
+	mv -f elf32-kvx.new elf32-kvx.c
+
+elf64-kvx.c : elfnn-kvx.c
+	rm -f elf64-kvx.c
+	echo "#line 1 \"$(srcdir)/elfnn-kvx.c\"" > elf64-kvx.new
+	sed -e s/NN/64/g < $(srcdir)/elfnn-kvx.c >> elf64-kvx.new
+	mv -f elf64-kvx.new elf64-kvx.c
+
 elf32-loongarch.c : elfnn-loongarch.c
 	$(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 4edfedee924..76c7e184dcd 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -468,6 +468,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -573,6 +574,7 @@ ALL_MACHINES = \
 	cpu-hppa.lo \
 	cpu-i386.lo \
 	cpu-iamcu.lo \
+	cpu-kvx.lo \
 	cpu-ia64.lo \
 	cpu-ip2k.lo \
 	cpu-iq2000.lo \
@@ -656,6 +658,7 @@ ALL_MACHINES_CFILES = \
 	cpu-hppa.c \
 	cpu-i386.c \
 	cpu-iamcu.c \
+	cpu-kvx.c \
 	cpu-ia64.c \
 	cpu-ip2k.c \
 	cpu-iq2000.c \
@@ -773,6 +776,8 @@ BFD32_BACKENDS = \
 	elfxx-x86.lo \
 	elf32-ip2k.lo \
 	elf32-iq2000.lo \
+	elf32-kvx.lo \
+	elfxx-kvx.lo \
 	elf32-lm32.lo \
 	elf32-m32c.lo \
 	elf32-m32r.lo \
@@ -908,6 +913,7 @@ BFD32_BACKENDS_CFILES = \
 	elfxx-x86.c \
 	elf32-ip2k.c \
 	elf32-iq2000.c \
+	elfxx-kvx.c \
 	elf32-lm32.c \
 	elf32-m32c.c \
 	elf32-m32r.c \
@@ -1013,6 +1019,8 @@ BFD64_BACKENDS = \
 	elf64-ia64.lo \
 	elf64-ia64-vms.lo \
 	elfxx-ia64.lo \
+	elfxx-kvx.lo \
+	elf64-kvx.lo \
 	elf32-loongarch.lo \
 	elf64-loongarch.lo \
 	elfxx-loongarch.lo \
@@ -1075,6 +1083,7 @@ BFD64_BACKENDS_CFILES = \
 	elfn32-mips.c \
 	elfxx-aarch64.c \
 	elfxx-ia64.c \
+	elfxx-kvx.c \
 	elfxx-loongarch.c \
 	elfxx-mips.c \
 	elfxx-riscv.c \
@@ -1137,6 +1146,7 @@ SOURCE_CFILES = \
 
 BUILD_CFILES = \
 	elf32-aarch64.c elf64-aarch64.c \
+	elf32-kvx.c elf64-kvx.c \
 	elf32-ia64.c elf64-ia64.c \
 	elf32-loongarch.c elf64-loongarch.c \
 	elf32-riscv.c elf64-riscv.c \
@@ -1483,6 +1493,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-iamcu.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-ip2k.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-iq2000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-kvx.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-lm32.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-loongarch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-m10200.Plo@am__quote@
@@ -1577,6 +1588,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ia64.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-ip2k.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-iq2000.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-kvx.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-lm32.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-loongarch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf32-m32c.Plo@am__quote@
@@ -1629,6 +1641,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-hppa.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64-vms.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-kvx.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-loongarch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf64-mmix.Plo@am__quote@
@@ -1644,6 +1657,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfn32-mips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-aarch64.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-ia64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-kvx.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-loongarch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-mips.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@
@@ -2348,6 +2362,18 @@ elf64-ia64.c : elfnn-ia64.c
 	$(AM_V_at)echo "#line 1 \"elfnn-ia64.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/NN/64/g < $< >> $@
 
+elf32-kvx.c : elfnn-kvx.c
+	rm -f elf32-kvx.c
+	echo "#line 1 \"$(srcdir)/elfnn-kvx.c\"" > elf32-kvx.new
+	sed -e s/NN/32/g < $(srcdir)/elfnn-kvx.c >> elf32-kvx.new
+	mv -f elf32-kvx.new elf32-kvx.c
+
+elf64-kvx.c : elfnn-kvx.c
+	rm -f elf64-kvx.c
+	echo "#line 1 \"$(srcdir)/elfnn-kvx.c\"" > elf64-kvx.new
+	sed -e s/NN/64/g < $(srcdir)/elfnn-kvx.c >> elf64-kvx.new
+	mv -f elf64-kvx.new elf64-kvx.c
+
 elf32-loongarch.c : elfnn-loongarch.c
 	$(AM_V_at)echo "#line 1 \"elfnn-loongarch.c\"" > $@
 	$(AM_V_GEN)$(SED) -e s/NN/32/g < $< >> $@
diff --git a/bfd/archures.c b/bfd/archures.c
index 5a2a76c3de1..b59979e60ac 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -515,6 +515,17 @@ DESCRIPTION
 .  bfd_arch_lm32,      {* Lattice Mico32.  *}
 .#define bfd_mach_lm32		1
 .  bfd_arch_microblaze,{* Xilinx MicroBlaze.  *}
+.  bfd_arch_kvx,        {* Kalray VLIW core of the MPPA processor family *}
+.#define bfd_mach_kv3_unknown       0
+.#define bfd_mach_kv3_1             1
+.#define bfd_mach_kv3_1_64          2
+.#define bfd_mach_kv3_1_usr         3
+.#define bfd_mach_kv3_2             4
+.#define bfd_mach_kv3_2_64          5
+.#define bfd_mach_kv3_2_usr         6
+.#define bfd_mach_kv4_1             7
+.#define bfd_mach_kv4_1_64          8
+.#define bfd_mach_kv4_1_usr         9
 .  bfd_arch_tilepro,   {* Tilera TILEPro.  *}
 .  bfd_arch_tilegx,    {* Tilera TILE-Gx.  *}
 .#define bfd_mach_tilepro	1
@@ -642,6 +653,7 @@ extern const bfd_arch_info_type bfd_iamcu_arch;
 extern const bfd_arch_info_type bfd_ia64_arch;
 extern const bfd_arch_info_type bfd_ip2k_arch;
 extern const bfd_arch_info_type bfd_iq2000_arch;
+extern const bfd_arch_info_type bfd_kvx_arch;
 extern const bfd_arch_info_type bfd_lm32_arch;
 extern const bfd_arch_info_type bfd_loongarch_arch;
 extern const bfd_arch_info_type bfd_m32c_arch;
@@ -730,6 +742,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
     &bfd_ia64_arch,
     &bfd_ip2k_arch,
     &bfd_iq2000_arch,
+    &bfd_kvx_arch,
     &bfd_lm32_arch,
     &bfd_loongarch_arch,
     &bfd_m32c_arch,
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e2deb107494..1c4f75ae244 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1771,6 +1771,17 @@ enum bfd_architecture
   bfd_arch_lm32,      /* Lattice Mico32.  */
 #define bfd_mach_lm32          1
   bfd_arch_microblaze,/* Xilinx MicroBlaze.  */
+  bfd_arch_kvx,        /* Kalray VLIW core of the MPPA processor family */
+#define bfd_mach_kv3_unknown       0
+#define bfd_mach_kv3_1             1
+#define bfd_mach_kv3_1_64          2
+#define bfd_mach_kv3_1_usr         3
+#define bfd_mach_kv3_2             4
+#define bfd_mach_kv3_2_64          5
+#define bfd_mach_kv3_2_usr         6
+#define bfd_mach_kv4_1             7
+#define bfd_mach_kv4_1_64          8
+#define bfd_mach_kv4_1_usr         9
   bfd_arch_tilepro,   /* Tilera TILEPro.  */
   bfd_arch_tilegx,    /* Tilera TILE-Gx.  */
 #define bfd_mach_tilepro       1
@@ -6522,6 +6533,106 @@ value in two words (with an imm instruction).  The relocation is
 relative offset from start of TEXT.  */
   BFD_RELOC_MICROBLAZE_64_TEXTREL,
 
+/* KVX pseudo relocation code to mark the start of the KVX
+relocation enumerators.  N.B. the order of the enumerators is
+important as several tables in the KVX bfd backend are indexed
+by these enumerators; make sure they are all synced.";  */
+  BFD_RELOC_KVX_RELOC_START,
+
+/* KVX null relocation code.  */
+  BFD_RELOC_KVX_NONE,
+
+/* KVX Relocations.  */
+  BFD_RELOC_KVX_16,
+  BFD_RELOC_KVX_32,
+  BFD_RELOC_KVX_64,
+  BFD_RELOC_KVX_S16_PCREL,
+  BFD_RELOC_KVX_PCREL17,
+  BFD_RELOC_KVX_PCREL27,
+  BFD_RELOC_KVX_32_PCREL,
+  BFD_RELOC_KVX_S37_PCREL_LO10,
+  BFD_RELOC_KVX_S37_PCREL_UP27,
+  BFD_RELOC_KVX_S43_PCREL_LO10,
+  BFD_RELOC_KVX_S43_PCREL_UP27,
+  BFD_RELOC_KVX_S43_PCREL_EX6,
+  BFD_RELOC_KVX_S64_PCREL_LO10,
+  BFD_RELOC_KVX_S64_PCREL_UP27,
+  BFD_RELOC_KVX_S64_PCREL_EX27,
+  BFD_RELOC_KVX_64_PCREL,
+  BFD_RELOC_KVX_S16,
+  BFD_RELOC_KVX_S32_LO5,
+  BFD_RELOC_KVX_S32_UP27,
+  BFD_RELOC_KVX_S37_LO10,
+  BFD_RELOC_KVX_S37_UP27,
+  BFD_RELOC_KVX_S37_GOTOFF_LO10,
+  BFD_RELOC_KVX_S37_GOTOFF_UP27,
+  BFD_RELOC_KVX_S43_GOTOFF_LO10,
+  BFD_RELOC_KVX_S43_GOTOFF_UP27,
+  BFD_RELOC_KVX_S43_GOTOFF_EX6,
+  BFD_RELOC_KVX_32_GOTOFF,
+  BFD_RELOC_KVX_64_GOTOFF,
+  BFD_RELOC_KVX_32_GOT,
+  BFD_RELOC_KVX_S37_GOT_LO10,
+  BFD_RELOC_KVX_S37_GOT_UP27,
+  BFD_RELOC_KVX_S43_GOT_LO10,
+  BFD_RELOC_KVX_S43_GOT_UP27,
+  BFD_RELOC_KVX_S43_GOT_EX6,
+  BFD_RELOC_KVX_64_GOT,
+  BFD_RELOC_KVX_GLOB_DAT,
+  BFD_RELOC_KVX_COPY,
+  BFD_RELOC_KVX_JMP_SLOT,
+  BFD_RELOC_KVX_RELATIVE,
+  BFD_RELOC_KVX_S43_LO10,
+  BFD_RELOC_KVX_S43_UP27,
+  BFD_RELOC_KVX_S43_EX6,
+  BFD_RELOC_KVX_S64_LO10,
+  BFD_RELOC_KVX_S64_UP27,
+  BFD_RELOC_KVX_S64_EX27,
+  BFD_RELOC_KVX_S37_GOTADDR_LO10,
+  BFD_RELOC_KVX_S37_GOTADDR_UP27,
+  BFD_RELOC_KVX_S43_GOTADDR_LO10,
+  BFD_RELOC_KVX_S43_GOTADDR_UP27,
+  BFD_RELOC_KVX_S43_GOTADDR_EX6,
+  BFD_RELOC_KVX_S64_GOTADDR_LO10,
+  BFD_RELOC_KVX_S64_GOTADDR_UP27,
+  BFD_RELOC_KVX_S64_GOTADDR_EX27,
+  BFD_RELOC_KVX_64_DTPMOD,
+  BFD_RELOC_KVX_64_DTPOFF,
+  BFD_RELOC_KVX_S37_TLS_DTPOFF_LO10,
+  BFD_RELOC_KVX_S37_TLS_DTPOFF_UP27,
+  BFD_RELOC_KVX_S43_TLS_DTPOFF_LO10,
+  BFD_RELOC_KVX_S43_TLS_DTPOFF_UP27,
+  BFD_RELOC_KVX_S43_TLS_DTPOFF_EX6,
+  BFD_RELOC_KVX_S37_TLS_GD_LO10,
+  BFD_RELOC_KVX_S37_TLS_GD_UP27,
+  BFD_RELOC_KVX_S43_TLS_GD_LO10,
+  BFD_RELOC_KVX_S43_TLS_GD_UP27,
+  BFD_RELOC_KVX_S43_TLS_GD_EX6,
+  BFD_RELOC_KVX_S37_TLS_LD_LO10,
+  BFD_RELOC_KVX_S37_TLS_LD_UP27,
+  BFD_RELOC_KVX_S43_TLS_LD_LO10,
+  BFD_RELOC_KVX_S43_TLS_LD_UP27,
+  BFD_RELOC_KVX_S43_TLS_LD_EX6,
+  BFD_RELOC_KVX_64_TPOFF,
+  BFD_RELOC_KVX_S37_TLS_IE_LO10,
+  BFD_RELOC_KVX_S37_TLS_IE_UP27,
+  BFD_RELOC_KVX_S43_TLS_IE_LO10,
+  BFD_RELOC_KVX_S43_TLS_IE_UP27,
+  BFD_RELOC_KVX_S43_TLS_IE_EX6,
+  BFD_RELOC_KVX_S37_TLS_LE_LO10,
+  BFD_RELOC_KVX_S37_TLS_LE_UP27,
+  BFD_RELOC_KVX_S43_TLS_LE_LO10,
+  BFD_RELOC_KVX_S43_TLS_LE_UP27,
+  BFD_RELOC_KVX_S43_TLS_LE_EX6,
+  BFD_RELOC_KVX_8,
+
+/* KVX pseudo relocation code to mark the end of the KVX
+relocation enumerators that have direct mapping to ELF reloc codes.
+There are a few more enumerators after this one; those are mainly
+used by the KVX assembler for the internal fixup or to select
+one of the above enumerators.  */
+  BFD_RELOC_KVX_RELOC_END,
+
 /* AArch64 pseudo relocation code to mark the start of the AArch64
 relocation enumerators.  N.B. the order of the enumerators is
 important as several tables in the AArch64 bfd backend are indexed
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 3b39ff36c00..29f1c77e11f 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -196,6 +196,7 @@ fido*)		 targ_archs=bfd_m68k_arch ;;
 hppa*)		 targ_archs=bfd_hppa_arch ;;
 i[3-7]86)	 targ_archs=bfd_i386_arch ;;
 ia16)		 targ_archs=bfd_i386_arch ;;
+kvx)		 targ_archs=bfd_kvx_arch ;;
 loongarch*)	 targ_archs=bfd_loongarch_arch ;;
 m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
 m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch bfd_m9s12x_arch bfd_m9s12xg_arch" ;;
@@ -797,6 +798,21 @@ case "${targ}" in
     targ_defvec=iq2000_elf32_vec
     ;;
 
+#ifdef BFD64
+  kvx-*-linux*)
+    targ_defvec=kvx_elf64_vec
+    want64=true
+    ;;
+#endif
+
+  kvx-*-*)
+    targ_defvec=kvx_elf32_vec
+    targ_selvecs="kvx_elf32_vec"
+#ifdef BFD64
+    targ64_selvecs=kvx_elf64_vec
+#endif
+    ;;
+
   lm32-*-elf | lm32-*-rtems*)
     targ_defvec=lm32_elf32_vec
     targ_selvecs=lm32_elf32_fdpic_vec
diff --git a/bfd/configure b/bfd/configure
index 77085136720..489531c0a7f 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13959,6 +13959,9 @@ do
     ia64_pei_vec)		 tb="$tb pei-ia64.lo pepigen.lo $coff"; target_size=64 ;;
     ip2k_elf32_vec)		 tb="$tb elf32-ip2k.lo elf32.lo $elf" ;;
     iq2000_elf32_vec)		 tb="$tb elf32-iq2000.lo elf32.lo $elf" ;;
+    kvx_elf32_vec)		 tb="$tb elf32-kvx.lo elfxx-kvx.lo elf32.lo $elf $ipa" ;;
+    kvx_elf64_vec)		 tb="$tb elf64-kvx.lo elfxx-kvx.lo elf64.lo $elf $ipa" ;;
+    kvx_elf64_linux_vec)	 tb="$tb elf64-kvx.lo elfxx-kvx.lo elf64.lo $elf $ipa" ;;
     lm32_elf32_vec)		 tb="$tb elf32-lm32.lo elf32.lo $elf" ;;
     lm32_elf32_fdpic_vec)	 tb="$tb elf32-lm32.lo elf32.lo $elf" ;;
     loongarch_elf32_vec)	 tb="$tb elf32-loongarch.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf" ;;
diff --git a/bfd/configure.ac b/bfd/configure.ac
index f044616f4d9..0d1cd814af6 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -495,6 +495,9 @@ do
     ia64_pei_vec)		 tb="$tb pei-ia64.lo pepigen.lo $coff"; target_size=64 ;;
     ip2k_elf32_vec)		 tb="$tb elf32-ip2k.lo elf32.lo $elf" ;;
     iq2000_elf32_vec)		 tb="$tb elf32-iq2000.lo elf32.lo $elf" ;;
+    kvx_elf32_vec)		 tb="$tb elf32-kvx.lo elfxx-kvx.lo elf32.lo $elf $ipa" ;;
+    kvx_elf64_vec)		 tb="$tb elf64-kvx.lo elfxx-kvx.lo elf64.lo $elf $ipa" ;;
+    kvx_elf64_linux_vec)	 tb="$tb elf64-kvx.lo elfxx-kvx.lo elf64.lo $elf $ipa" ;;
     lm32_elf32_vec)		 tb="$tb elf32-lm32.lo elf32.lo $elf" ;;
     lm32_elf32_fdpic_vec)	 tb="$tb elf32-lm32.lo elf32.lo $elf" ;;
     loongarch_elf32_vec)	 tb="$tb elf32-loongarch.lo elfxx-loongarch.lo elf32.lo elf-ifunc.lo $elf" ;;
diff --git a/bfd/cpu-kvx.c b/bfd/cpu-kvx.c
new file mode 100644
index 00000000000..61d9d5daf69
--- /dev/null
+++ b/bfd/cpu-kvx.c
@@ -0,0 +1,124 @@
+/* BFD support for KVX.
+   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+   Contributed by Kalray SA.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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/>.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+/* This routine is provided two arch_infos and returns if machines
+   are compatible.
+*/
+
+static const bfd_arch_info_type *
+kvx_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b)
+{
+  long amach =  a->mach, bmach =  b->mach;
+  /* If a & b are for different architecture we can do nothing.  */
+  if (a->arch != b->arch)
+    return NULL;
+
+  if ((amach == bfd_mach_kv3_1_64 && bmach == bfd_mach_kv3_1_usr)
+      || (amach == bfd_mach_kv3_2_64 && bmach == bfd_mach_kv3_2_usr))
+    return b;
+
+  if ((bmach == bfd_mach_kv3_1_64 && amach == bfd_mach_kv3_1_usr)
+      || (bmach == bfd_mach_kv3_2_64 && amach == bfd_mach_kv3_2_usr))
+    return a;
+
+  /* Otherwise if either a or b is the 'default' machine
+   * then it can be polymorphed into the other.
+   * This will enable to execute merge_private_bfd_data
+   */
+  if (a->the_default)
+    return b;
+
+  if (b->the_default)
+    return a;
+
+  /* We do not want to transmute some machine into another one */
+  if (amach != bmach)
+    return NULL;
+
+  /* If a & b are for the same machine then all is well.  */
+  if (amach == bmach)
+    return a;
+
+  return NULL;
+}
+
+static bool
+scan (const struct bfd_arch_info *info, const char *string)
+{
+  /* First test for an exact match.  */
+  if (strcasecmp (string, info->printable_name) == 0)
+    return true;
+
+  /* Finally check for the default architecture.  */
+  if (strcasecmp (string, "kvx") == 0)
+    return info->the_default;
+
+  return false;
+}
+
+#define N(addr_bits, machine, print, default, next)            \
+{                                                              \
+  32,                          /* 32 bits in a word.  */       \
+  addr_bits,                   /* bits in an address.  */      \
+  8,                           /* 8 bits in a byte.  */        \
+  bfd_arch_kvx,                                                 \
+  machine,                     /* Machine number.  */          \
+  "kvx",                        /* Architecture name.   */      \
+  print,                       /* Printable name.  */          \
+  4,                           /* Section align power.  */     \
+  default,                     /* Is this the default ?  */    \
+  kvx_compatible,					       \
+  scan,                                                        \
+  bfd_arch_default_fill,                                       \
+  next,                                                \
+          0                                            \
+}
+
+
+const bfd_arch_info_type bfd_kv4_1_usr_arch =
+  N (64 , bfd_mach_kv4_1_usr , "kvx:kv4-1:usr" , false , NULL);
+
+const bfd_arch_info_type bfd_kv3_2_usr_arch =
+  N (64 , bfd_mach_kv3_2_usr , "kvx:kv3-2:usr" , false , &bfd_kv4_1_usr_arch);
+
+const bfd_arch_info_type bfd_kv3_1_usr_arch =
+  N (64 , bfd_mach_kv3_1_usr , "kvx:kv3-1:usr" , false , &bfd_kv3_2_usr_arch);
+
+const bfd_arch_info_type bfd_kv4_1_64_arch =
+  N (64 , bfd_mach_kv4_1_64  , "kvx:kv4-1:64"  , false , &bfd_kv3_1_usr_arch);
+
+const bfd_arch_info_type bfd_kv3_2_64_arch =
+  N (64 , bfd_mach_kv3_2_64  , "kvx:kv3-2:64"  , false , &bfd_kv4_1_64_arch);
+
+const bfd_arch_info_type bfd_kv3_1_64_arch =
+  N (64 , bfd_mach_kv3_1_64  , "kvx:kv3-1:64"  , false , &bfd_kv3_2_64_arch);
+
+const bfd_arch_info_type bfd_kv4_1_arch =
+  N (32 , bfd_mach_kv4_1     , "kvx:kv4-1"     , false , &bfd_kv3_1_64_arch);
+
+const bfd_arch_info_type bfd_kv3_2_arch =
+  N (32 , bfd_mach_kv3_2     , "kvx:kv3-2"     , false , &bfd_kv4_1_arch);
+
+const bfd_arch_info_type bfd_kvx_arch =
+  N (32 , bfd_mach_kv3_1     , "kvx:kv3-1"     , true  , &bfd_kv3_2_arch);
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index ec856764519..869e86b7749 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -545,6 +545,7 @@ enum elf_target_id
   HPPA64_ELF_DATA,
   I386_ELF_DATA,
   IA64_ELF_DATA,
+  KVX_ELF_DATA,
   LM32_ELF_DATA,
   LARCH_ELF_DATA,
   M32R_ELF_DATA,
diff --git a/bfd/elfnn-kvx.c b/bfd/elfnn-kvx.c
new file mode 100644
index 00000000000..77ff2483a28
--- /dev/null
+++ b/bfd/elfnn-kvx.c
@@ -0,0 +1,4805 @@
+/* KVX-specific support for NN-bit ELF.
+   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+   Contributed by Kalray SA.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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/>.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libiberty.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "bfdlink.h"
+#include "objalloc.h"
+#include "elf/kvx.h"
+#include "elfxx-kvx.h"
+
+#define ARCH_SIZE	NN
+
+#if ARCH_SIZE == 64
+#define LOG_FILE_ALIGN	3
+#endif
+
+#if ARCH_SIZE == 32
+#define LOG_FILE_ALIGN	2
+#endif
+
+#define IS_KVX_TLS_RELOC(R_TYPE)			\
+  ((R_TYPE) == BFD_RELOC_KVX_S37_TLS_LE_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_LE_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LE_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LE_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LE_EX6	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_DTPOFF_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_DTPOFF_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_DTPOFF_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_DTPOFF_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_DTPOFF_EX6	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_IE_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_IE_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_IE_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_IE_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_IE_EX6	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_GD_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_GD_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_GD_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_GD_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_GD_EX6	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_LD_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S37_TLS_LD_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LD_LO10	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LD_UP27	\
+   || (R_TYPE) == BFD_RELOC_KVX_S43_TLS_LD_EX6	\
+   )
+
+#define IS_KVX_TLS_RELAX_RELOC(R_TYPE) 0
+
+#define ELIMINATE_COPY_RELOCS 0
+
+/* Return size of a relocation entry.  HTAB is the bfd's
+   elf_kvx_link_hash_entry.  */
+#define RELOC_SIZE(HTAB) (sizeof (ElfNN_External_Rela))
+
+/* GOT Entry size - 8 bytes in ELF64 and 4 bytes in ELF32.  */
+#define GOT_ENTRY_SIZE                  (ARCH_SIZE / 8)
+#define PLT_ENTRY_SIZE                  (32)
+
+#define PLT_SMALL_ENTRY_SIZE            (4*4)
+
+/* Encoding of the nop instruction */
+#define INSN_NOP 0x00f0037f
+
+#define kvx_compute_jump_table_size(htab)		\
+  (((htab)->root.srelplt == NULL) ? 0			\
+   : (htab)->root.srelplt->reloc_count * GOT_ENTRY_SIZE)
+
+static const bfd_byte elfNN_kvx_small_plt0_entry[PLT_ENTRY_SIZE] =
+{
+ /* FIXME KVX: no first entry, not used yet */
+  0
+};
+
+/* Per function entry in a procedure linkage table looks like this
+   if the distance between the PLTGOT and the PLT is < 4GB use
+   these PLT entries.  */
+static const bfd_byte elfNN_kvx_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
+{
+  0x10, 0x00, 0xc4, 0x0f,       /* get $r16 = $pc     ;; */
+#if ARCH_SIZE == 32
+  0x10, 0x00, 0x40, 0xb0,       /* lwz $r16 = 0[$r16]   ;; */
+#else
+  0x10, 0x00, 0x40, 0xb8,       /* ld $r16 = 0[$r16] ;; */
+#endif
+  0x00, 0x00, 0x00, 0x18,       /* upper 27 bits for LSU */
+  0x10, 0x00, 0xd8, 0x0f,	/* igoto $r16          ;; */
+};
+
+/* Long stub use 43bits format of make. */
+static const uint32_t elfNN_kvx_long_branch_stub[] =
+{
+  0xe0400000,      /* make $r16 = LO10<emm43> EX6<imm43> */
+  0x00000000,      /* UP27<imm43> ;; */
+  0x0fd80010,      /* igoto "r16  ;; */
+};
+
+#define elf_info_to_howto               elfNN_kvx_info_to_howto
+#define elf_info_to_howto_rel           elfNN_kvx_info_to_howto
+
+#define KVX_ELF_ABI_VERSION		0
+
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
+#define ALL_ONES (~ (bfd_vma) 0)
+
+/* Indexed by the bfd interal reloc enumerators.
+   Therefore, the table needs to be synced with BFD_RELOC_KVX_*
+   in reloc.c.   */
+
+#define KVX_KV3_V1_KV3_V2_KV4_V1
+#include "elfxx-kvx-relocs.h"
+#undef KVX_KV3_V1_KV3_V2_KV4_V1
+
+/* Given HOWTO, return the bfd internal relocation enumerator.  */
+
+static bfd_reloc_code_real_type
+elfNN_kvx_bfd_reloc_from_howto (reloc_howto_type *howto)
+{
+  const int size = (int) ARRAY_SIZE (elf_kvx_howto_table);
+  const ptrdiff_t offset = howto - elf_kvx_howto_table;
+
+  if (offset >= 0 && offset < size)
+    return BFD_RELOC_KVX_RELOC_START + offset + 1;
+
+  return BFD_RELOC_KVX_RELOC_START + 1;
+}
+
+/* Given R_TYPE, return the bfd internal relocation enumerator.  */
+
+static bfd_reloc_code_real_type
+elfNN_kvx_bfd_reloc_from_type (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type)
+{
+  static bool initialized_p = false;
+  /* Indexed by R_TYPE, values are offsets in the howto_table.  */
+  static unsigned int offsets[R_KVX_end];
+
+  if (!initialized_p)
+    {
+      unsigned int i;
+
+      for (i = 0; i < ARRAY_SIZE (elf_kvx_howto_table); ++i)
+        offsets[elf_kvx_howto_table[i].type] = i;
+
+      initialized_p = true;
+    }
+
+  /* PR 17512: file: b371e70a.  */
+  if (r_type >= R_KVX_end)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return BFD_RELOC_KVX_RELOC_END;
+    }
+
+  return (BFD_RELOC_KVX_RELOC_START + 1) + offsets[r_type];
+}
+
+struct elf_kvx_reloc_map
+{
+  bfd_reloc_code_real_type from;
+  bfd_reloc_code_real_type to;
+};
+
+/* Map bfd generic reloc to KVX-specific reloc.  */
+static const struct elf_kvx_reloc_map elf_kvx_reloc_map[] =
+{
+  {BFD_RELOC_NONE, BFD_RELOC_KVX_NONE},
+
+  /* Basic data relocations.  */
+  {BFD_RELOC_CTOR, BFD_RELOC_KVX_NN},
+  {BFD_RELOC_64, BFD_RELOC_KVX_64},
+  {BFD_RELOC_32, BFD_RELOC_KVX_32},
+  {BFD_RELOC_16, BFD_RELOC_KVX_16},
+  {BFD_RELOC_8,  BFD_RELOC_KVX_8},
+
+  {BFD_RELOC_64_PCREL, BFD_RELOC_KVX_64_PCREL},
+  {BFD_RELOC_32_PCREL, BFD_RELOC_KVX_32_PCREL},
+};
+
+/* Given the bfd internal relocation enumerator in CODE, return the
+   corresponding howto entry.  */
+
+static reloc_howto_type *
+elfNN_kvx_howto_from_bfd_reloc (bfd_reloc_code_real_type code)
+{
+  unsigned int i;
+
+  /* Convert bfd generic reloc to KVX-specific reloc.  */
+  if (code < BFD_RELOC_KVX_RELOC_START || code > BFD_RELOC_KVX_RELOC_END)
+    for (i = 0; i < ARRAY_SIZE (elf_kvx_reloc_map) ; i++)
+      if (elf_kvx_reloc_map[i].from == code)
+	{
+	  code = elf_kvx_reloc_map[i].to;
+	  break;
+	}
+
+  if (code > BFD_RELOC_KVX_RELOC_START && code < BFD_RELOC_KVX_RELOC_END)
+      return &elf_kvx_howto_table[code - (BFD_RELOC_KVX_RELOC_START + 1)];
+
+  return NULL;
+}
+
+static reloc_howto_type *
+elfNN_kvx_howto_from_type (bfd *abfd, unsigned int r_type)
+{
+  bfd_reloc_code_real_type val;
+  reloc_howto_type *howto;
+
+#if ARCH_SIZE == 32
+  if (r_type > 256)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+#endif
+
+  val = elfNN_kvx_bfd_reloc_from_type (abfd, r_type);
+  howto = elfNN_kvx_howto_from_bfd_reloc (val);
+
+  if (howto != NULL)
+    return howto;
+
+  bfd_set_error (bfd_error_bad_value);
+  return NULL;
+}
+
+static bool
+elfNN_kvx_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc,
+			     Elf_Internal_Rela *elf_reloc)
+{
+  unsigned int r_type;
+
+  r_type = ELFNN_R_TYPE (elf_reloc->r_info);
+  bfd_reloc->howto = elfNN_kvx_howto_from_type (abfd, r_type);
+
+  if (bfd_reloc->howto == NULL)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
+      return false;
+    }
+  return true;
+}
+
+static reloc_howto_type *
+elfNN_kvx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 bfd_reloc_code_real_type code)
+{
+  reloc_howto_type *howto = elfNN_kvx_howto_from_bfd_reloc (code);
+
+  if (howto != NULL)
+    return howto;
+
+  bfd_set_error (bfd_error_bad_value);
+  return NULL;
+}
+
+static reloc_howto_type *
+elfNN_kvx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+				 const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (elf_kvx_howto_table); ++i)
+    if (elf_kvx_howto_table[i].name != NULL
+	&& strcasecmp (elf_kvx_howto_table[i].name, r_name) == 0)
+      return &elf_kvx_howto_table[i];
+
+  return NULL;
+}
+
+#define TARGET_LITTLE_SYM               kvx_elfNN_vec
+#define TARGET_LITTLE_NAME              "elfNN-kvx"
+
+/* The linker script knows the section names for placement.
+   The entry_names are used to do simple name mangling on the stubs.
+   Given a function name, and its type, the stub can be found. The
+   name can be changed. The only requirement is the %s be present.  */
+#define STUB_ENTRY_NAME   "__%s_veneer"
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+#define ELF_DYNAMIC_INTERPRETER     "/lib/ld.so.1"
+
+
+/* PCREL 27 is signed-extended and scaled by 4 */
+#define KVX_MAX_FWD_CALL_OFFSET \
+  (((1 << 26) - 1) << 2)
+#define KVX_MAX_BWD_CALL_OFFSET \
+  (-((1 << 26) << 2))
+
+/* Check that the destination of the call is within the PCREL27
+   range. */
+static int
+kvx_valid_call_p (bfd_vma value, bfd_vma place)
+{
+  bfd_signed_vma offset = (bfd_signed_vma) (value - place);
+  return (offset <= KVX_MAX_FWD_CALL_OFFSET
+	  && offset >= KVX_MAX_BWD_CALL_OFFSET);
+}
+
+/* Section name for stubs is the associated section name plus this
+   string.  */
+#define STUB_SUFFIX ".stub"
+
+enum elf_kvx_stub_type
+{
+  kvx_stub_none,
+  kvx_stub_long_branch,
+};
+
+struct elf_kvx_stub_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+
+  /* The stub section.  */
+  asection *stub_sec;
+
+  /* Offset within stub_sec of the beginning of this stub.  */
+  bfd_vma stub_offset;
+
+  /* Given the symbol's value and its section we can determine its final
+     value when building the stubs (so the stub knows where to jump).  */
+  bfd_vma target_value;
+  asection *target_section;
+
+  enum elf_kvx_stub_type stub_type;
+
+  /* The symbol table entry, if any, that this was derived from.  */
+  struct elf_kvx_link_hash_entry *h;
+
+  /* Destination symbol type */
+  unsigned char st_type;
+
+  /* Where this stub is being called from, or, in the case of combined
+     stub sections, the first input section in the group.  */
+  asection *id_sec;
+
+  /* The name for the local symbol at the start of this stub.  The
+     stub name in the hash table has to be unique; this does not, so
+     it can be friendlier.  */
+  char *output_name;
+};
+
+/* Used to build a map of a section.  This is required for mixed-endian
+   code/data.  */
+
+typedef struct elf_elf_section_map
+{
+  bfd_vma vma;
+  char type;
+}
+elf_kvx_section_map;
+
+
+typedef struct _kvx_elf_section_data
+{
+  struct bfd_elf_section_data elf;
+  unsigned int mapcount;
+  unsigned int mapsize;
+  elf_kvx_section_map *map;
+}
+_kvx_elf_section_data;
+
+#define elf_kvx_section_data(sec) \
+  ((_kvx_elf_section_data *) elf_section_data (sec))
+
+struct elf_kvx_local_symbol
+{
+  unsigned int got_type;
+  bfd_signed_vma got_refcount;
+  bfd_vma got_offset;
+};
+
+struct elf_kvx_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* local symbol descriptors */
+  struct elf_kvx_local_symbol *locals;
+
+  /* Zero to warn when linking objects with incompatible enum sizes.  */
+  int no_enum_size_warning;
+
+  /* Zero to warn when linking objects with incompatible wchar_t sizes.  */
+  int no_wchar_size_warning;
+};
+
+#define elf_kvx_tdata(bfd)				\
+  ((struct elf_kvx_obj_tdata *) (bfd)->tdata.any)
+
+#define elf_kvx_locals(bfd) (elf_kvx_tdata (bfd)->locals)
+
+#define is_kvx_elf(bfd)				\
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour	\
+   && elf_tdata (bfd) != NULL				\
+   && elf_object_id (bfd) == KVX_ELF_DATA)
+
+static bool
+elfNN_kvx_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_kvx_obj_tdata),
+				  KVX_ELF_DATA);
+}
+
+#define elf_kvx_hash_entry(ent) \
+  ((struct elf_kvx_link_hash_entry *)(ent))
+
+#define GOT_UNKNOWN    0
+#define GOT_NORMAL     1
+
+#define GOT_TLS_GD     2
+#define GOT_TLS_IE     4
+#define GOT_TLS_LD     8
+
+/* KVX ELF linker hash entry.  */
+struct elf_kvx_link_hash_entry
+{
+  struct elf_link_hash_entry root;
+
+  /* Since PLT entries have variable size, we need to record the
+     index into .got.plt instead of recomputing it from the PLT
+     offset.  */
+  bfd_signed_vma plt_got_offset;
+
+  /* Bit mask representing the type of GOT entry(s) if any required by
+     this symbol.  */
+  unsigned int got_type;
+
+  /* A pointer to the most recently used stub hash entry against this
+     symbol.  */
+  struct elf_kvx_stub_hash_entry *stub_cache;
+};
+
+/* Get the KVX elf linker hash table from a link_info structure.  */
+#define elf_kvx_hash_table(info)					\
+  ((struct elf_kvx_link_hash_table *) ((info)->hash))
+
+#define kvx_stub_hash_lookup(table, string, create, copy)		\
+  ((struct elf_kvx_stub_hash_entry *)				\
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
+/* KVX ELF linker hash table.  */
+struct elf_kvx_link_hash_table
+{
+  /* The main hash table.  */
+  struct elf_link_hash_table root;
+
+  /* Nonzero to force PIC branch veneers.  */
+  int pic_veneer;
+
+  /* The number of bytes in the initial entry in the PLT.  */
+  bfd_size_type plt_header_size;
+
+  /* The number of bytes in the subsequent PLT etries.  */
+  bfd_size_type plt_entry_size;
+
+  /* The bytes of the subsequent PLT entry.  */
+  const bfd_byte *plt_entry;
+
+  /* Short-cuts to get to dynamic linker sections.  */
+  asection *sdynbss;
+  asection *srelbss;
+
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
+
+  /* For convenience in allocate_dynrelocs.  */
+  bfd *obfd;
+
+  /* The amount of space used by the reserved portion of the sgotplt
+     section, plus whatever space is used by the jump slots.  */
+  bfd_vma sgotplt_jump_table_size;
+
+  /* The stub hash table.  */
+  struct bfd_hash_table stub_hash_table;
+
+  /* Linker stub bfd.  */
+  bfd *stub_bfd;
+
+  /* Linker call-backs.  */
+  asection *(*add_stub_section) (const char *, asection *);
+  void (*layout_sections_again) (void);
+
+  /* Array to keep track of which stub sections have been created, and
+     information on stub grouping.  */
+  struct map_stub
+  {
+    /* This is the section to which stubs in the group will be
+       attached.  */
+    asection *link_sec;
+    /* The stub section.  */
+    asection *stub_sec;
+  } *stub_group;
+
+  /* Assorted information used by elfNN_kvx_size_stubs.  */
+  unsigned int bfd_count;
+  unsigned int top_index;
+  asection **input_list;
+};
+
+/* Create an entry in an KVX ELF linker hash table.  */
+
+static struct bfd_hash_entry *
+elfNN_kvx_link_hash_newfunc (struct bfd_hash_entry *entry,
+				 struct bfd_hash_table *table,
+				 const char *string)
+{
+  struct elf_kvx_link_hash_entry *ret =
+    (struct elf_kvx_link_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == NULL)
+    ret = bfd_hash_allocate (table,
+			     sizeof (struct elf_kvx_link_hash_entry));
+  if (ret == NULL)
+    return (struct bfd_hash_entry *) ret;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct elf_kvx_link_hash_entry *)
+	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+				     table, string));
+  if (ret != NULL)
+    {
+      ret->got_type = GOT_UNKNOWN;
+      ret->plt_got_offset = (bfd_vma) - 1;
+      ret->stub_cache = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize an entry in the stub hash table.  */
+
+static struct bfd_hash_entry *
+stub_hash_newfunc (struct bfd_hash_entry *entry,
+		   struct bfd_hash_table *table, const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+				 sizeof (struct
+					 elf_kvx_stub_hash_entry));
+      if (entry == NULL)
+	return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf_kvx_stub_hash_entry *eh;
+
+      /* Initialize the local fields.  */
+      eh = (struct elf_kvx_stub_hash_entry *) entry;
+      eh->stub_sec = NULL;
+      eh->stub_offset = 0;
+      eh->target_value = 0;
+      eh->target_section = NULL;
+      eh->stub_type = kvx_stub_none;
+      eh->h = NULL;
+      eh->id_sec = NULL;
+    }
+
+  return entry;
+}
+
+/* Copy the extra info we tack onto an elf_link_hash_entry.  */
+
+static void
+elfNN_kvx_copy_indirect_symbol (struct bfd_link_info *info,
+				    struct elf_link_hash_entry *dir,
+				    struct elf_link_hash_entry *ind)
+{
+  struct elf_kvx_link_hash_entry *edir, *eind;
+
+  edir = (struct elf_kvx_link_hash_entry *) dir;
+  eind = (struct elf_kvx_link_hash_entry *) ind;
+
+  if (ind->root.type == bfd_link_hash_indirect)
+    {
+      /* Copy over PLT info.  */
+      if (dir->got.refcount <= 0)
+	{
+	  edir->got_type = eind->got_type;
+	  eind->got_type = GOT_UNKNOWN;
+	}
+    }
+
+  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
+/* Destroy a KVX elf linker hash table.  */
+
+static void
+elfNN_kvx_link_hash_table_free (bfd *obfd)
+{
+  struct elf_kvx_link_hash_table *ret
+    = (struct elf_kvx_link_hash_table *) obfd->link.hash;
+
+  bfd_hash_table_free (&ret->stub_hash_table);
+  _bfd_elf_link_hash_table_free (obfd);
+}
+
+/* Create a KVX elf linker hash table.  */
+
+static struct bfd_link_hash_table *
+elfNN_kvx_link_hash_table_create (bfd *abfd)
+{
+  struct elf_kvx_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_kvx_link_hash_table);
+
+  ret = bfd_zmalloc (amt);
+  if (ret == NULL)
+    return NULL;
+
+  if (!_bfd_elf_link_hash_table_init
+      (&ret->root, abfd, elfNN_kvx_link_hash_newfunc,
+       sizeof (struct elf_kvx_link_hash_entry), KVX_ELF_DATA))
+    {
+      free (ret);
+      return NULL;
+    }
+
+  ret->plt_header_size = PLT_ENTRY_SIZE;
+  ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
+  ret->plt_entry = elfNN_kvx_small_plt_entry;
+
+  ret->obfd = abfd;
+
+  if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
+			    sizeof (struct elf_kvx_stub_hash_entry)))
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+
+  ret->root.root.hash_table_free = elfNN_kvx_link_hash_table_free;
+
+  return &ret->root.root;
+}
+
+static bfd_reloc_status_type
+kvx_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
+              bfd_vma offset, bfd_vma value)
+{
+  reloc_howto_type *howto;
+  bfd_vma place;
+
+  howto = elfNN_kvx_howto_from_type (input_bfd, r_type);
+  place = (input_section->output_section->vma + input_section->output_offset
+	   + offset);
+
+  r_type = elfNN_kvx_bfd_reloc_from_type (input_bfd, r_type);
+  value = _bfd_kvx_elf_resolve_relocation (r_type, place, value, 0, false);
+  return _bfd_kvx_elf_put_addend (input_bfd,
+                                  input_section->contents + offset, r_type,
+                                  howto, value);
+}
+
+/* Determine the type of stub needed, if any, for a call.  */
+
+static enum elf_kvx_stub_type
+kvx_type_of_stub (asection *input_sec,
+		      const Elf_Internal_Rela *rel,
+		      asection *sym_sec,
+		      unsigned char st_type,
+		      bfd_vma destination)
+{
+  bfd_vma location;
+  bfd_signed_vma branch_offset;
+  unsigned int r_type;
+  enum elf_kvx_stub_type stub_type = kvx_stub_none;
+
+  if (st_type != STT_FUNC
+      && (sym_sec == input_sec))
+    return stub_type;
+
+  /* Determine where the call point is.  */
+  location = (input_sec->output_offset
+              + input_sec->output_section->vma + rel->r_offset);
+
+  branch_offset = (bfd_signed_vma) (destination - location);
+
+  r_type = ELFNN_R_TYPE (rel->r_info);
+
+  /* We don't want to redirect any old unconditional jump in this way,
+     only one which is being used for a sibcall, where it is
+     acceptable for the R16 and R17 registers to be clobbered.  */
+  if (r_type == R_KVX_PCREL27
+      && (branch_offset > KVX_MAX_FWD_CALL_OFFSET
+	  || branch_offset < KVX_MAX_BWD_CALL_OFFSET))
+    {
+      stub_type = kvx_stub_long_branch;
+    }
+
+  return stub_type;
+}
+
+/* Build a name for an entry in the stub hash table.  */
+
+static char *
+elfNN_kvx_stub_name (const asection *input_section,
+                     const asection *sym_sec,
+                     const struct elf_kvx_link_hash_entry *hash,
+                     const Elf_Internal_Rela *rel)
+{
+  char *stub_name;
+  bfd_size_type len;
+
+  if (hash)
+    {
+      len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 16 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+	snprintf (stub_name, len, "%08x_%s+%" PRIx64 "x",
+		  (unsigned int) input_section->id,
+		  hash->root.root.root.string,
+		  rel->r_addend);
+    }
+  else
+    {
+      len = 8 + 1 + 8 + 1 + 8 + 1 + 16 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+	snprintf (stub_name, len, "%08x_%x:%x+%" PRIx64 "x",
+		  (unsigned int) input_section->id,
+		  (unsigned int) sym_sec->id,
+		  (unsigned int) ELFNN_R_SYM (rel->r_info),
+		  rel->r_addend);
+    }
+
+  return stub_name;
+}
+
+/* Return true if symbol H should be hashed in the `.gnu.hash' section.  For
+   executable PLT slots where the executable never takes the address of those
+   functions, the function symbols are not added to the hash table.  */
+
+static bool
+elf_kvx_hash_symbol (struct elf_link_hash_entry *h)
+{
+  if (h->plt.offset != (bfd_vma) -1
+      && !h->def_regular
+      && !h->pointer_equality_needed)
+    return false;
+
+  return _bfd_elf_hash_symbol (h);
+}
+
+
+/* Look up an entry in the stub hash.  Stub entries are cached because
+   creating the stub name takes a bit of time.  */
+
+static struct elf_kvx_stub_hash_entry *
+elfNN_kvx_get_stub_entry (const asection *input_section,
+                          const asection *sym_sec,
+                          struct elf_link_hash_entry *hash,
+                          const Elf_Internal_Rela *rel,
+                          struct elf_kvx_link_hash_table *htab)
+{
+  struct elf_kvx_stub_hash_entry *stub_entry;
+  struct elf_kvx_link_hash_entry *h =
+    (struct elf_kvx_link_hash_entry *) hash;
+  const asection *id_sec;
+
+  if ((input_section->flags & SEC_CODE) == 0)
+    return NULL;
+
+  /* If this input section is part of a group of sections sharing one
+     stub section, then use the id of the first section in the group.
+     Stub names need to include a section id, as there may well be
+     more than one stub used to reach say, printf, and we need to
+     distinguish between them.  */
+  id_sec = htab->stub_group[input_section->id].link_sec;
+
+  if (h != NULL && h->stub_cache != NULL
+      && h->stub_cache->h == h && h->stub_cache->id_sec == id_sec)
+    {
+      stub_entry = h->stub_cache;
+    }
+  else
+    {
+      char *stub_name;
+
+      stub_name = elfNN_kvx_stub_name (id_sec, sym_sec, h, rel);
+      if (stub_name == NULL)
+	return NULL;
+
+      stub_entry = kvx_stub_hash_lookup (&htab->stub_hash_table,
+                                         stub_name, false, false);
+      if (h != NULL)
+	h->stub_cache = stub_entry;
+
+      free (stub_name);
+    }
+
+  return stub_entry;
+}
+
+
+/* Create a stub section.  */
+
+static asection *
+_bfd_kvx_create_stub_section (asection *section,
+                              struct elf_kvx_link_hash_table *htab)
+
+{
+  size_t namelen;
+  bfd_size_type len;
+  char *s_name;
+
+  namelen = strlen (section->name);
+  len = namelen + sizeof (STUB_SUFFIX);
+  s_name = bfd_alloc (htab->stub_bfd, len);
+  if (s_name == NULL)
+    return NULL;
+
+  memcpy (s_name, section->name, namelen);
+  memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+  return (*htab->add_stub_section) (s_name, section);
+}
+
+
+/* Find or create a stub section for a link section.
+
+   Fix or create the stub section used to collect stubs attached to
+   the specified link section.  */
+
+static asection *
+_bfd_kvx_get_stub_for_link_section (asection *link_section,
+                                    struct elf_kvx_link_hash_table *htab)
+{
+  if (htab->stub_group[link_section->id].stub_sec == NULL)
+    htab->stub_group[link_section->id].stub_sec
+      = _bfd_kvx_create_stub_section (link_section, htab);
+  return htab->stub_group[link_section->id].stub_sec;
+}
+
+
+/* Find or create a stub section in the stub group for an input
+   section.  */
+
+static asection *
+_bfd_kvx_create_or_find_stub_sec (asection *section,
+                                  struct elf_kvx_link_hash_table *htab)
+{
+  asection *link_sec = htab->stub_group[section->id].link_sec;
+  return _bfd_kvx_get_stub_for_link_section (link_sec, htab);
+}
+
+
+/* Add a new stub entry in the stub group associated with an input
+   section to the stub hash.  Not all fields of the new stub entry are
+   initialised.  */
+
+static struct elf_kvx_stub_hash_entry *
+_bfd_kvx_add_stub_entry_in_group (const char *stub_name,
+                                  asection *section,
+                                  struct elf_kvx_link_hash_table *htab)
+{
+  asection *link_sec;
+  asection *stub_sec;
+  struct elf_kvx_stub_hash_entry *stub_entry;
+
+  link_sec = htab->stub_group[section->id].link_sec;
+  stub_sec = _bfd_kvx_create_or_find_stub_sec (section, htab);
+
+  /* Enter this entry into the linker stub hash table.  */
+  stub_entry = kvx_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+                                     true, false);
+  if (stub_entry == NULL)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: cannot create stub entry %s"),
+                          section->owner, stub_name);
+      return NULL;
+    }
+
+  stub_entry->stub_sec = stub_sec;
+  stub_entry->stub_offset = 0;
+  stub_entry->id_sec = link_sec;
+
+  return stub_entry;
+}
+
+static bool
+kvx_build_one_stub (struct bfd_hash_entry *gen_entry,
+                    void *in_arg)
+{
+  struct elf_kvx_stub_hash_entry *stub_entry;
+  asection *stub_sec;
+  bfd *stub_bfd;
+  bfd_byte *loc;
+  bfd_vma sym_value;
+  unsigned int template_size;
+  const uint32_t *template;
+  unsigned int i;
+  struct bfd_link_info *info;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf_kvx_stub_hash_entry *) gen_entry;
+
+  info = (struct bfd_link_info *) in_arg;
+
+  /* Fail if the target section could not be assigned to an output
+     section.  The user should fix his linker script.  */
+  if (stub_entry->target_section->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
+			      "Retry without "
+			      "--enable-non-contiguous-regions.\n"),
+			    stub_entry->target_section);
+
+  stub_sec = stub_entry->stub_sec;
+
+  /* Make a note of the offset within the stubs for this entry.  */
+  stub_entry->stub_offset = stub_sec->size;
+  loc = stub_sec->contents + stub_entry->stub_offset;
+
+  stub_bfd = stub_sec->owner;
+
+  /* This is the address of the stub destination.  */
+  sym_value = (stub_entry->target_value
+	       + stub_entry->target_section->output_offset
+	       + stub_entry->target_section->output_section->vma);
+
+  switch (stub_entry->stub_type)
+    {
+    case kvx_stub_long_branch:
+      template = elfNN_kvx_long_branch_stub;
+      template_size = sizeof (elfNN_kvx_long_branch_stub);
+      break;
+    default:
+      abort ();
+    }
+
+  for (i = 0; i < (template_size / sizeof template[0]); i++)
+    {
+      bfd_putl32 (template[i], loc);
+      loc += 4;
+    }
+
+  stub_sec->size += template_size;
+
+  switch (stub_entry->stub_type)
+    {
+    case kvx_stub_long_branch:
+      /*
+	The stub uses a make insn with 43bits immediate.
+	We need to apply 3 relocations:
+	     BFD_RELOC_KVX_S43_LO10
+	     BFD_RELOC_KVX_S43_UP27
+	     BFD_RELOC_KVX_S43_EX6
+      */
+      if (kvx_relocate (R_KVX_S43_LO10, stub_bfd, stub_sec,
+                        stub_entry->stub_offset , sym_value) != bfd_reloc_ok)
+        BFD_FAIL ();
+      if (kvx_relocate (R_KVX_S43_EX6, stub_bfd, stub_sec,
+                        stub_entry->stub_offset , sym_value) != bfd_reloc_ok)
+        BFD_FAIL ();
+      if (kvx_relocate (R_KVX_S43_UP27, stub_bfd, stub_sec,
+                        stub_entry->stub_offset  + 4, sym_value) != bfd_reloc_ok)
+      	BFD_FAIL ();
+      break;
+    default:
+      abort ();
+    }
+
+  return true;
+}
+
+/* As above, but don't actually build the stub.  Just bump offset so
+   we know stub section sizes.  */
+
+static bool
+kvx_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED)
+{
+  struct elf_kvx_stub_hash_entry *stub_entry;
+  int size;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf_kvx_stub_hash_entry *) gen_entry;
+
+  switch (stub_entry->stub_type)
+    {
+    case kvx_stub_long_branch:
+      size = sizeof (elfNN_kvx_long_branch_stub);
+      break;
+    default:
+      abort ();
+    }
+
+  stub_entry->stub_sec->size += size;
+  return true;
+}
+
+/* External entry points for sizing and building linker stubs.  */
+
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
+
+int
+elfNN_kvx_setup_section_lists (bfd *output_bfd,
+                               struct bfd_link_info *info)
+{
+  bfd *input_bfd;
+  unsigned int bfd_count;
+  unsigned int top_id, top_index;
+  asection *section;
+  asection **input_list, **list;
+  bfd_size_type amt;
+  struct elf_kvx_link_hash_table *htab =
+    elf_kvx_hash_table (info);
+
+  if (!is_elf_hash_table ((const struct bfd_link_hash_table *)htab))
+    return 0;
+
+  /* Count the number of input BFDs and find the top input section id.  */
+  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+       input_bfd != NULL; input_bfd = input_bfd->link.next)
+    {
+      bfd_count += 1;
+      for (section = input_bfd->sections;
+	   section != NULL; section = section->next)
+	{
+	  if (top_id < section->id)
+	    top_id = section->id;
+	}
+    }
+  htab->bfd_count = bfd_count;
+
+  amt = sizeof (struct map_stub) * (top_id + 1);
+  htab->stub_group = bfd_zmalloc (amt);
+  if (htab->stub_group == NULL)
+    return -1;
+
+  /* We can't use output_bfd->section_count here to find the top output
+     section index as some sections may have been removed, and
+     _bfd_strip_section_from_output doesn't renumber the indices.  */
+  for (section = output_bfd->sections, top_index = 0;
+       section != NULL; section = section->next)
+    {
+      if (top_index < section->index)
+	top_index = section->index;
+    }
+
+  htab->top_index = top_index;
+  amt = sizeof (asection *) * (top_index + 1);
+  input_list = bfd_malloc (amt);
+  htab->input_list = input_list;
+  if (input_list == NULL)
+    return -1;
+
+  /* For sections we aren't interested in, mark their entries with a
+     value we can check later.  */
+  list = input_list + top_index;
+  do
+    *list = bfd_abs_section_ptr;
+  while (list-- != input_list);
+
+  for (section = output_bfd->sections;
+       section != NULL; section = section->next)
+    {
+      if ((section->flags & SEC_CODE) != 0)
+	input_list[section->index] = NULL;
+    }
+
+  return 1;
+}
+
+/* Used by elfNN_kvx_next_input_section and group_sections.  */
+#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
+
+/* The linker repeatedly calls this function for each input section,
+   in the order that input sections are linked into output sections.
+   Build lists of input sections to determine groupings between which
+   we may insert linker stubs.  */
+
+void
+elfNN_kvx_next_input_section (struct bfd_link_info *info, asection *isec)
+{
+  struct elf_kvx_link_hash_table *htab =
+    elf_kvx_hash_table (info);
+
+  if (isec->output_section->index <= htab->top_index)
+    {
+      asection **list = htab->input_list + isec->output_section->index;
+
+      if (*list != bfd_abs_section_ptr)
+	{
+	  /* Steal the link_sec pointer for our list.  */
+	  /* This happens to make the list in reverse order,
+	     which is what we want.  */
+	  PREV_SEC (isec) = *list;
+	  *list = isec;
+	}
+    }
+}
+
+/* See whether we can group stub sections together.  Grouping stub
+   sections may result in fewer stubs.  More importantly, we need to
+   put all .init* and .fini* stubs at the beginning of the .init or
+   .fini output sections respectively, because glibc splits the
+   _init and _fini functions into multiple parts.  Putting a stub in
+   the middle of a function is not a good idea.  */
+
+static void
+group_sections (struct elf_kvx_link_hash_table *htab,
+		bfd_size_type stub_group_size,
+		bool stubs_always_after_branch)
+{
+  asection **list = htab->input_list;
+
+  do
+    {
+      asection *tail = *list;
+      asection *head;
+
+      if (tail == bfd_abs_section_ptr)
+	continue;
+
+      /* Reverse the list: we must avoid placing stubs at the
+	 beginning of the section because the beginning of the text
+	 section may be required for an interrupt vector in bare metal
+	 code.  */
+#define NEXT_SEC PREV_SEC
+      head = NULL;
+      while (tail != NULL)
+	{
+	  /* Pop from tail.  */
+	  asection *item = tail;
+	  tail = PREV_SEC (item);
+
+	  /* Push on head.  */
+	  NEXT_SEC (item) = head;
+	  head = item;
+	}
+
+      while (head != NULL)
+	{
+	  asection *curr;
+	  asection *next;
+	  bfd_vma stub_group_start = head->output_offset;
+	  bfd_vma end_of_next;
+
+	  curr = head;
+	  while (NEXT_SEC (curr) != NULL)
+	    {
+	      next = NEXT_SEC (curr);
+	      end_of_next = next->output_offset + next->size;
+	      if (end_of_next - stub_group_start >= stub_group_size)
+		/* End of NEXT is too far from start, so stop.  */
+		break;
+	      /* Add NEXT to the group.  */
+	      curr = next;
+	    }
+
+	  /* OK, the size from the start to the start of CURR is less
+	     than stub_group_size and thus can be handled by one stub
+	     section.  (Or the head section is itself larger than
+	     stub_group_size, in which case we may be toast.)
+	     We should really be keeping track of the total size of
+	     stubs added here, as stubs contribute to the final output
+	     section size.  */
+	  do
+	    {
+	      next = NEXT_SEC (head);
+	      /* Set up this stub group.  */
+	      htab->stub_group[head->id].link_sec = curr;
+	    }
+	  while (head != curr && (head = next) != NULL);
+
+	  /* But wait, there's more!  Input sections up to stub_group_size
+	     bytes after the stub section can be handled by it too.  */
+	  if (!stubs_always_after_branch)
+	    {
+	      stub_group_start = curr->output_offset + curr->size;
+
+	      while (next != NULL)
+		{
+		  end_of_next = next->output_offset + next->size;
+		  if (end_of_next - stub_group_start >= stub_group_size)
+		    /* End of NEXT is too far from stubs, so stop.  */
+		    break;
+		  /* Add NEXT to the stub group.  */
+		  head = next;
+		  next = NEXT_SEC (head);
+		  htab->stub_group[head->id].link_sec = curr;
+		}
+	    }
+	  head = next;
+	}
+    }
+  while (list++ != htab->input_list + htab->top_index);
+
+  free (htab->input_list);
+}
+
+static void
+_bfd_kvx_resize_stubs (struct elf_kvx_link_hash_table *htab)
+{
+  asection *section;
+
+  /* OK, we've added some stubs.  Find out the new size of the
+     stub sections.  */
+  for (section = htab->stub_bfd->sections;
+       section != NULL; section = section->next)
+    {
+      /* Ignore non-stub sections.  */
+      if (!strstr (section->name, STUB_SUFFIX))
+	continue;
+      section->size = 0;
+    }
+
+  bfd_hash_traverse (&htab->stub_hash_table, kvx_size_one_stub, htab);
+}
+
+/* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
+
+bool
+kvx_elfNN_init_stub_bfd (struct bfd_link_info *info,
+			bfd *stub_bfd)
+{
+  struct elf_kvx_link_hash_table *htab;
+
+  elf_elfheader (stub_bfd)->e_ident[EI_CLASS] = ELFCLASSNN;
+
+/* Always hook our dynamic sections into the first bfd, which is the
+   linker created stub bfd.  This ensures that the GOT header is at
+   the start of the output TOC section.  */
+  htab = elf_kvx_hash_table (info);
+  if (htab == NULL)
+    return false;
+
+  return true;
+}
+
+/* Determine and set the size of the stub section for a final link.
+
+   The basic idea here is to examine all the relocations looking for
+   PC-relative calls to a target that is unreachable with a 27bits
+   immediate (found in call and goto).  */
+
+bool
+elfNN_kvx_size_stubs (bfd *output_bfd,
+		     bfd *stub_bfd,
+		     struct bfd_link_info *info,
+		     bfd_signed_vma group_size,
+		     asection * (*add_stub_section) (const char *,
+						     asection *),
+		     void (*layout_sections_again) (void))
+{
+  bfd_size_type stub_group_size;
+  bool stubs_always_before_branch;
+  bool stub_changed = false;
+  struct elf_kvx_link_hash_table *htab = elf_kvx_hash_table (info);
+
+  /* Propagate mach to stub bfd, because it may not have been
+     finalized when we created stub_bfd.  */
+  bfd_set_arch_mach (stub_bfd, bfd_get_arch (output_bfd),
+		     bfd_get_mach (output_bfd));
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
+  stubs_always_before_branch = group_size < 0;
+  if (group_size < 0)
+    stub_group_size = -group_size;
+  else
+    stub_group_size = group_size;
+
+  if (stub_group_size == 1)
+    {
+      /* Default values.  */
+      /* KVX branch range is +-256MB. The value used is 1MB less.  */
+      stub_group_size = 255 * 1024 * 1024;
+    }
+
+  group_sections (htab, stub_group_size, stubs_always_before_branch);
+
+  (*htab->layout_sections_again) ();
+
+  while (1)
+    {
+      bfd *input_bfd;
+
+      for (input_bfd = info->input_bfds;
+	   input_bfd != NULL; input_bfd = input_bfd->link.next)
+	{
+	  Elf_Internal_Shdr *symtab_hdr;
+	  asection *section;
+	  Elf_Internal_Sym *local_syms = NULL;
+
+	  if (!is_kvx_elf (input_bfd)
+	      || (input_bfd->flags & BFD_LINKER_CREATED) != 0)
+	    continue;
+
+	  /* We'll need the symbol table in a second.  */
+	  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+	  if (symtab_hdr->sh_info == 0)
+	    continue;
+
+	  /* Walk over each section attached to the input bfd.  */
+	  for (section = input_bfd->sections;
+	       section != NULL; section = section->next)
+	    {
+	      Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+	      /* If there aren't any relocs, then there's nothing more
+		 to do.  */
+	      if ((section->flags & SEC_RELOC) == 0
+		  || section->reloc_count == 0
+		  || (section->flags & SEC_CODE) == 0)
+		continue;
+
+	      /* If this section is a link-once section that will be
+		 discarded, then don't create any stubs.  */
+	      if (section->output_section == NULL
+		  || section->output_section->owner != output_bfd)
+		continue;
+
+	      /* Get the relocs.  */
+	      internal_relocs
+		= _bfd_elf_link_read_relocs (input_bfd, section, NULL,
+					     NULL, info->keep_memory);
+	      if (internal_relocs == NULL)
+		goto error_ret_free_local;
+
+	      /* Now examine each relocation.  */
+	      irela = internal_relocs;
+	      irelaend = irela + section->reloc_count;
+	      for (; irela < irelaend; irela++)
+		{
+		  unsigned int r_type, r_indx;
+		  enum elf_kvx_stub_type stub_type;
+		  struct elf_kvx_stub_hash_entry *stub_entry;
+		  asection *sym_sec;
+		  bfd_vma sym_value;
+		  bfd_vma destination;
+		  struct elf_kvx_link_hash_entry *hash;
+		  const char *sym_name;
+		  char *stub_name;
+		  const asection *id_sec;
+		  unsigned char st_type;
+		  bfd_size_type len;
+
+		  r_type = ELFNN_R_TYPE (irela->r_info);
+		  r_indx = ELFNN_R_SYM (irela->r_info);
+
+		  if (r_type >= (unsigned int) R_KVX_end)
+		    {
+		      bfd_set_error (bfd_error_bad_value);
+		    error_ret_free_internal:
+		      if (elf_section_data (section)->relocs == NULL)
+			free (internal_relocs);
+		      goto error_ret_free_local;
+		    }
+
+		  /* Only look for stubs on unconditional branch and
+		     branch and link instructions.  */
+		  /* This catches CALL and GOTO insn */
+		  if (r_type != (unsigned int) R_KVX_PCREL27)
+		    continue;
+
+		  /* Now determine the call target, its name, value,
+		     section.  */
+		  sym_sec = NULL;
+		  sym_value = 0;
+		  destination = 0;
+		  hash = NULL;
+		  sym_name = NULL;
+		  if (r_indx < symtab_hdr->sh_info)
+		    {
+		      /* It's a local symbol.  */
+		      Elf_Internal_Sym *sym;
+		      Elf_Internal_Shdr *hdr;
+
+		      if (local_syms == NULL)
+			{
+			  local_syms
+			    = (Elf_Internal_Sym *) symtab_hdr->contents;
+			  if (local_syms == NULL)
+			    local_syms
+			      = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+						      symtab_hdr->sh_info, 0,
+						      NULL, NULL, NULL);
+			  if (local_syms == NULL)
+			    goto error_ret_free_internal;
+			}
+
+		      sym = local_syms + r_indx;
+		      hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+		      sym_sec = hdr->bfd_section;
+		      if (!sym_sec)
+			/* This is an undefined symbol.  It can never
+			   be resolved.  */
+			continue;
+
+		      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+			sym_value = sym->st_value;
+		      destination = (sym_value + irela->r_addend
+				     + sym_sec->output_offset
+				     + sym_sec->output_section->vma);
+		      st_type = ELF_ST_TYPE (sym->st_info);
+		      sym_name
+			= bfd_elf_string_from_elf_section (input_bfd,
+							   symtab_hdr->sh_link,
+							   sym->st_name);
+		    }
+		  else
+		    {
+		      int e_indx;
+
+		      e_indx = r_indx - symtab_hdr->sh_info;
+		      hash = ((struct elf_kvx_link_hash_entry *)
+			      elf_sym_hashes (input_bfd)[e_indx]);
+
+		      while (hash->root.root.type == bfd_link_hash_indirect
+			     || hash->root.root.type == bfd_link_hash_warning)
+			hash = ((struct elf_kvx_link_hash_entry *)
+				hash->root.root.u.i.link);
+
+		      if (hash->root.root.type == bfd_link_hash_defined
+			  || hash->root.root.type == bfd_link_hash_defweak)
+			{
+			  struct elf_kvx_link_hash_table *globals =
+			    elf_kvx_hash_table (info);
+			  sym_sec = hash->root.root.u.def.section;
+			  sym_value = hash->root.root.u.def.value;
+			  /* For a destination in a shared library,
+			     use the PLT stub as target address to
+			     decide whether a branch stub is
+			     needed.  */
+			  if (globals->root.splt != NULL && hash != NULL
+			      && hash->root.plt.offset != (bfd_vma) - 1)
+			    {
+			      sym_sec = globals->root.splt;
+			      sym_value = hash->root.plt.offset;
+			      if (sym_sec->output_section != NULL)
+				destination = (sym_value
+					       + sym_sec->output_offset
+					       +
+					       sym_sec->output_section->vma);
+			    }
+			  else if (sym_sec->output_section != NULL)
+			    destination = (sym_value + irela->r_addend
+					   + sym_sec->output_offset
+					   + sym_sec->output_section->vma);
+			}
+		      else if (hash->root.root.type == bfd_link_hash_undefined
+			       || (hash->root.root.type
+				   == bfd_link_hash_undefweak))
+			{
+			  /* For a shared library, use the PLT stub as
+			     target address to decide whether a long
+			     branch stub is needed.
+			     For absolute code, they cannot be handled.  */
+			  struct elf_kvx_link_hash_table *globals =
+			    elf_kvx_hash_table (info);
+
+			  if (globals->root.splt != NULL && hash != NULL
+			      && hash->root.plt.offset != (bfd_vma) - 1)
+			    {
+			      sym_sec = globals->root.splt;
+			      sym_value = hash->root.plt.offset;
+			      if (sym_sec->output_section != NULL)
+				destination = (sym_value
+					       + sym_sec->output_offset
+					       +
+					       sym_sec->output_section->vma);
+			    }
+			  else
+			    continue;
+			}
+		      else
+			{
+			  bfd_set_error (bfd_error_bad_value);
+			  goto error_ret_free_internal;
+			}
+		      st_type = ELF_ST_TYPE (hash->root.type);
+		      sym_name = hash->root.root.root.string;
+		    }
+
+		  /* Determine what (if any) linker stub is needed.  */
+		  stub_type = kvx_type_of_stub (section, irela, sym_sec,
+                                                st_type, destination);
+		  if (stub_type == kvx_stub_none)
+		    continue;
+
+		  /* Support for grouping stub sections.  */
+		  id_sec = htab->stub_group[section->id].link_sec;
+
+		  /* Get the name of this stub.  */
+		  stub_name = elfNN_kvx_stub_name (id_sec, sym_sec, hash,
+						  irela);
+		  if (!stub_name)
+		    goto error_ret_free_internal;
+
+		  stub_entry =
+		    kvx_stub_hash_lookup (&htab->stub_hash_table,
+					 stub_name, false, false);
+		  if (stub_entry != NULL)
+		    {
+		      /* The proper stub has already been created.  */
+		      free (stub_name);
+                      /* Always update this stub's target since it may have
+			 changed after layout.  */
+		      stub_entry->target_value = sym_value + irela->r_addend;
+		      continue;
+		    }
+
+		  stub_entry = _bfd_kvx_add_stub_entry_in_group
+		    (stub_name, section, htab);
+		  if (stub_entry == NULL)
+		    {
+		      free (stub_name);
+		      goto error_ret_free_internal;
+		    }
+
+		  stub_entry->target_value = sym_value + irela->r_addend;
+		  stub_entry->target_section = sym_sec;
+		  stub_entry->stub_type = stub_type;
+		  stub_entry->h = hash;
+		  stub_entry->st_type = st_type;
+
+		  if (sym_name == NULL)
+		    sym_name = "unnamed";
+		  len = sizeof (STUB_ENTRY_NAME) + strlen (sym_name);
+		  stub_entry->output_name = bfd_alloc (htab->stub_bfd, len);
+		  if (stub_entry->output_name == NULL)
+		    {
+		      free (stub_name);
+		      goto error_ret_free_internal;
+		    }
+
+		  snprintf (stub_entry->output_name, len, STUB_ENTRY_NAME,
+			    sym_name);
+
+		  stub_changed = true;
+		}
+
+	      /* We're done with the internal relocs, free them.  */
+	      if (elf_section_data (section)->relocs == NULL)
+		free (internal_relocs);
+	    }
+	}
+
+      if (!stub_changed)
+	break;
+
+      _bfd_kvx_resize_stubs (htab);
+
+      /* Ask the linker to do its stuff.  */
+      (*htab->layout_sections_again) ();
+      stub_changed = false;
+    }
+
+  return true;
+
+error_ret_free_local:
+  return false;
+
+}
+
+/* Build all the stubs associated with the current output file.  The
+   stubs are kept in a hash table attached to the main linker hash
+   table.  We also set up the .plt entries for statically linked PIC
+   functions here.  This function is called via kvx_elf_finish in the
+   linker.  */
+
+bool
+elfNN_kvx_build_stubs (struct bfd_link_info *info)
+{
+  asection *stub_sec;
+  struct bfd_hash_table *table;
+  struct elf_kvx_link_hash_table *htab;
+
+  htab = elf_kvx_hash_table (info);
+
+  for (stub_sec = htab->stub_bfd->sections;
+       stub_sec != NULL; stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Ignore non-stub sections.  */
+      if (!strstr (stub_sec->name, STUB_SUFFIX))
+	continue;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->size;
+      stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+	return false;
+      stub_sec->size = 0;
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  table = &htab->stub_hash_table;
+  bfd_hash_traverse (table, kvx_build_one_stub, info);
+
+  return true;
+}
+
+static bfd_vma
+kvx_calculate_got_entry_vma (struct elf_link_hash_entry *h,
+				 struct elf_kvx_link_hash_table
+				 *globals, struct bfd_link_info *info,
+				 bfd_vma value, bfd *output_bfd,
+				 bool *unresolved_reloc_p)
+{
+  bfd_vma off = (bfd_vma) - 1;
+  asection *basegot = globals->root.sgot;
+  bool dyn = globals->root.dynamic_sections_created;
+
+  if (h != NULL)
+    {
+      BFD_ASSERT (basegot != NULL);
+      off = h->got.offset;
+      BFD_ASSERT (off != (bfd_vma) - 1);
+      if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+	  || (bfd_link_pic (info)
+	      && SYMBOL_REFERENCES_LOCAL (info, h))
+	  || (ELF_ST_VISIBILITY (h->other)
+	      && h->root.type == bfd_link_hash_undefweak))
+	{
+	  /* This is actually a static link, or it is a -Bsymbolic link
+	     and the symbol is defined locally.  We must initialize this
+	     entry in the global offset table.  Since the offset must
+	     always be a multiple of 8 (4 in the case of ILP32), we use
+	     the least significant bit to record whether we have
+	     initialized it already.
+	     When doing a dynamic link, we create a .rel(a).got relocation
+	     entry to initialize the value.  This is done in the
+	     finish_dynamic_symbol routine.  */
+	  if ((off & 1) != 0)
+	    off &= ~1;
+	  else
+	    {
+	      bfd_put_NN (output_bfd, value, basegot->contents + off);
+	      h->got.offset |= 1;
+	    }
+	}
+      else
+	*unresolved_reloc_p = false;
+    }
+
+  return off;
+}
+
+static unsigned int
+kvx_reloc_got_type (bfd_reloc_code_real_type r_type)
+{
+  switch (r_type)
+    {
+      /* Extracted with:
+	 awk 'match ($0, /HOWTO.*R_(KVX.*_GOT(OFF)?(64)?_.*),/,ary) {print "case BFD_RELOC_" ary[1] ":";}' elfxx-kvxc.def
+	 */
+    case BFD_RELOC_KVX_S37_GOTOFF_LO10:
+    case BFD_RELOC_KVX_S37_GOTOFF_UP27:
+
+    case BFD_RELOC_KVX_S37_GOT_LO10:
+    case BFD_RELOC_KVX_S37_GOT_UP27:
+
+    case BFD_RELOC_KVX_S43_GOTOFF_LO10:
+    case BFD_RELOC_KVX_S43_GOTOFF_UP27:
+    case BFD_RELOC_KVX_S43_GOTOFF_EX6:
+
+    case BFD_RELOC_KVX_S43_GOT_LO10:
+    case BFD_RELOC_KVX_S43_GOT_UP27:
+    case BFD_RELOC_KVX_S43_GOT_EX6:
+      return GOT_NORMAL;
+ 
+    case BFD_RELOC_KVX_S37_TLS_GD_LO10:
+    case BFD_RELOC_KVX_S37_TLS_GD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_GD_LO10:
+    case BFD_RELOC_KVX_S43_TLS_GD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_GD_EX6:
+      return GOT_TLS_GD;
+
+    case BFD_RELOC_KVX_S37_TLS_LD_LO10:
+    case BFD_RELOC_KVX_S37_TLS_LD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_LD_LO10:
+    case BFD_RELOC_KVX_S43_TLS_LD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_LD_EX6:
+      return GOT_TLS_LD;
+
+    case BFD_RELOC_KVX_S37_TLS_IE_LO10:
+    case BFD_RELOC_KVX_S37_TLS_IE_UP27:
+    case BFD_RELOC_KVX_S43_TLS_IE_LO10:
+    case BFD_RELOC_KVX_S43_TLS_IE_UP27:
+    case BFD_RELOC_KVX_S43_TLS_IE_EX6:
+      return GOT_TLS_IE;
+
+    default:
+      break;
+    }
+  return GOT_UNKNOWN;
+}
+
+static bool
+kvx_can_relax_tls (bfd *input_bfd ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+		       bfd_reloc_code_real_type r_type ATTRIBUTE_UNUSED,
+		       struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
+		       unsigned long r_symndx ATTRIBUTE_UNUSED)
+{
+  if (! IS_KVX_TLS_RELAX_RELOC (r_type))
+    return false;
+
+  /* Relaxing hook. Disabled on KVX. */
+  /* See elfnn-aarch64.c */
+  return true;
+}
+
+/* Given the relocation code R_TYPE, return the relaxed bfd reloc
+   enumerator.  */
+
+static bfd_reloc_code_real_type
+kvx_tls_transition (bfd *input_bfd,
+			struct bfd_link_info *info,
+			unsigned int r_type,
+			struct elf_link_hash_entry *h,
+			unsigned long r_symndx)
+{
+  bfd_reloc_code_real_type bfd_r_type
+    = elfNN_kvx_bfd_reloc_from_type (input_bfd, r_type);
+
+  if (! kvx_can_relax_tls (input_bfd, info, bfd_r_type, h, r_symndx))
+    return bfd_r_type;
+
+  return bfd_r_type;
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving R_KVX_*_TLS_GD_* and R_KVX_*_TLS_LD_* relocation.  */
+
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving R_KVX_*_TLS_IE_* and R_KVX_*_TLS_LE_* relocations.  */
+
+static bfd_vma
+tpoff_base (struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  BFD_ASSERT (htab->tls_sec != NULL);
+
+  bfd_vma base = align_power ((bfd_vma) 0,
+			      htab->tls_sec->alignment_power);
+  return htab->tls_sec->vma - base;
+}
+
+static bfd_vma *
+symbol_got_offset_ref (bfd *input_bfd, struct elf_link_hash_entry *h,
+		       unsigned long r_symndx)
+{
+  /* Calculate the address of the GOT entry for symbol
+     referred to in h.  */
+  if (h != NULL)
+    return &h->got.offset;
+  else
+    {
+      /* local symbol */
+      struct elf_kvx_local_symbol *l;
+
+      l = elf_kvx_locals (input_bfd);
+      return &l[r_symndx].got_offset;
+    }
+}
+
+static void
+symbol_got_offset_mark (bfd *input_bfd, struct elf_link_hash_entry *h,
+			unsigned long r_symndx)
+{
+  bfd_vma *p;
+  p = symbol_got_offset_ref (input_bfd, h, r_symndx);
+  *p |= 1;
+}
+
+static int
+symbol_got_offset_mark_p (bfd *input_bfd, struct elf_link_hash_entry *h,
+			  unsigned long r_symndx)
+{
+  bfd_vma value;
+  value = * symbol_got_offset_ref (input_bfd, h, r_symndx);
+  return value & 1;
+}
+
+static bfd_vma
+symbol_got_offset (bfd *input_bfd, struct elf_link_hash_entry *h,
+		   unsigned long r_symndx)
+{
+  bfd_vma value;
+  value = * symbol_got_offset_ref (input_bfd, h, r_symndx);
+  value &= ~1;
+  return value;
+}
+
+/* N_ONES produces N one bits, without overflowing machine arithmetic.  */
+#define N_ONES(n) (((((bfd_vma) 1 << ((n) -1)) - 1) << 1) | 1)
+
+/*
+ * This is a copy/paste + modification from
+ * reloc.c:_bfd_relocate_contents. Relocations are applied to 32bits
+ * words, so all overflow checks will overflow for values above
+ * 32bits.
+ */
+static bfd_reloc_status_type
+check_signed_overflow (enum complain_overflow complain_on_overflow,
+		       bfd_reloc_code_real_type bfd_r_type, bfd *input_bfd,
+		       bfd_vma relocation)
+{
+  bfd_reloc_status_type flag = bfd_reloc_ok;
+  bfd_vma addrmask, fieldmask, signmask, ss;
+  bfd_vma a, b, sum;
+  bfd_vma x = 0;
+
+  /* These usually come from howto struct. As we don't check for
+   * values fitting in bitfields or in subpart of words, we set all
+   * these to values to check as if the field is starting from first
+   * bit.
+   */
+  unsigned int rightshift = 0;
+  unsigned int bitpos = 0;
+  unsigned int bitsize = 0;
+  bfd_vma src_mask = -1;
+
+  /* Only regular symbol relocations are checked here. Others
+     relocations (GOT, TLS) could be checked if the need is
+     confirmed. At the moment, we keep previous behavior
+     (ie. unchecked) for those. */
+  switch (bfd_r_type)
+    {
+    case BFD_RELOC_KVX_S37_LO10:
+    case BFD_RELOC_KVX_S37_UP27:
+      bitsize = 37;
+      break;
+
+    case BFD_RELOC_KVX_S32_LO5:
+    case BFD_RELOC_KVX_S32_UP27:
+      bitsize = 32;
+      break;
+
+    case BFD_RELOC_KVX_S43_LO10:
+    case BFD_RELOC_KVX_S43_UP27:
+    case BFD_RELOC_KVX_S43_EX6:
+      bitsize = 43;
+      break;
+
+    case BFD_RELOC_KVX_S64_LO10:
+    case BFD_RELOC_KVX_S64_UP27:
+    case BFD_RELOC_KVX_S64_EX27:
+      bitsize = 64;
+      break;
+
+    default:
+      return bfd_reloc_ok;
+    }
+
+  /* direct copy/paste from reloc.c below */
+
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (bitsize);
+  signmask = ~fieldmask;
+  addrmask = (N_ONES (bfd_arch_bits_per_address (input_bfd))
+	      | (fieldmask << rightshift));
+  a = (relocation & addrmask) >> rightshift;
+  b = (x & src_mask & addrmask) >> bitpos;
+  addrmask >>= rightshift;
+
+  switch (complain_on_overflow)
+    {
+    case complain_overflow_signed:
+      /* If any sign bits are set, all sign bits must be set.
+	 That is, A must be a valid negative address after
+	 shifting.  */
+      signmask = ~(fieldmask >> 1);
+      /* Fall thru */
+
+    case complain_overflow_bitfield:
+      /* Much like the signed check, but for a field one bit
+	 wider.  We allow a bitfield to represent numbers in the
+	 range -2**n to 2**n-1, where n is the number of bits in the
+	 field.  Note that when bfd_vma is 32 bits, a 32-bit reloc
+	 can't overflow, which is exactly what we want.  */
+      ss = a & signmask;
+      if (ss != 0 && ss != (addrmask & signmask))
+	flag = bfd_reloc_overflow;
+
+      /* We only need this next bit of code if the sign bit of B
+	 is below the sign bit of A.  This would only happen if
+	 SRC_MASK had fewer bits than BITSIZE.  Note that if
+	 SRC_MASK has more bits than BITSIZE, we can get into
+	 trouble; we would need to verify that B is in range, as
+	 we do for A above.  */
+      ss = ((~src_mask) >> 1) & src_mask;
+      ss >>= bitpos;
+
+      /* Set all the bits above the sign bit.  */
+      b = (b ^ ss) - ss;
+
+      /* Now we can do the addition.  */
+      sum = a + b;
+
+      /* See if the result has the correct sign.  Bits above the
+	 sign bit are junk now; ignore them.  If the sum is
+	 positive, make sure we did not have all negative inputs;
+	 if the sum is negative, make sure we did not have all
+	 positive inputs.  The test below looks only at the sign
+	 bits, and it really just
+	 SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM)
+
+	 We mask with addrmask here to explicitly allow an address
+	 wrap-around.  The Linux kernel relies on it, and it is
+	 the only way to write assembler code which can run when
+	 loaded at a location 0x80000000 away from the location at
+	 which it is linked.  */
+      if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask)
+	flag = bfd_reloc_overflow;
+      break;
+
+    case complain_overflow_unsigned:
+      /* Checking for an unsigned overflow is relatively easy:
+	 trim the addresses and add, and trim the result as well.
+	 Overflow is normally indicated when the result does not
+	 fit in the field.  However, we also need to consider the
+	 case when, e.g., fieldmask is 0x7fffffff or smaller, an
+	 input is 0x80000000, and bfd_vma is only 32 bits; then we
+	 will get sum == 0, but there is an overflow, since the
+	 inputs did not fit in the field.  Instead of doing a
+	 separate test, we can check for this by or-ing in the
+	 operands when testing for the sum overflowing its final
+	 field.  */
+      sum = (a + b) & addrmask;
+      if ((a | b | sum) & signmask)
+	flag = bfd_reloc_overflow;
+      break;
+
+    default:
+      abort ();
+    }
+  return flag;
+}
+
+/* Perform a relocation as part of a final link.  */
+static bfd_reloc_status_type
+elfNN_kvx_final_link_relocate (reloc_howto_type *howto,
+				   bfd *input_bfd,
+				   bfd *output_bfd,
+				   asection *input_section,
+				   bfd_byte *contents,
+				   Elf_Internal_Rela *rel,
+				   bfd_vma value,
+				   struct bfd_link_info *info,
+				   asection *sym_sec,
+				   struct elf_link_hash_entry *h,
+				   bool *unresolved_reloc_p,
+				   bool save_addend,
+				   bfd_vma *saved_addend,
+				   Elf_Internal_Sym *sym)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned int r_type = howto->type;
+  bfd_reloc_code_real_type bfd_r_type
+    = elfNN_kvx_bfd_reloc_from_howto (howto);
+  bfd_reloc_code_real_type new_bfd_r_type;
+  unsigned long r_symndx;
+  bfd_byte *hit_data = contents + rel->r_offset;
+  bfd_vma place, off;
+  bfd_signed_vma signed_addend;
+  struct elf_kvx_link_hash_table *globals;
+  bool weak_undef_p;
+  asection *base_got;
+  bfd_reloc_status_type rret = bfd_reloc_ok;
+  bool resolved_to_zero;
+  globals = elf_kvx_hash_table (info);
+
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
+
+  BFD_ASSERT (is_kvx_elf (input_bfd));
+
+  r_symndx = ELFNN_R_SYM (rel->r_info);
+
+  /* It is possible to have linker relaxations on some TLS access
+     models.  Update our information here.  */
+  new_bfd_r_type = kvx_tls_transition (input_bfd, info, r_type, h, r_symndx);
+  if (new_bfd_r_type != bfd_r_type)
+    {
+      bfd_r_type = new_bfd_r_type;
+      howto = elfNN_kvx_howto_from_bfd_reloc (bfd_r_type);
+      BFD_ASSERT (howto != NULL);
+      r_type = howto->type;
+    }
+
+  place = input_section->output_section->vma
+    + input_section->output_offset + rel->r_offset;
+
+  /* Get addend, accumulating the addend for consecutive relocs
+     which refer to the same offset.  */
+  signed_addend = saved_addend ? *saved_addend : 0;
+  signed_addend += rel->r_addend;
+
+  weak_undef_p = (h ? h->root.type == bfd_link_hash_undefweak
+		  : bfd_is_und_section (sym_sec));
+  resolved_to_zero = (h != NULL
+		      && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
+  switch (bfd_r_type)
+    {
+    case BFD_RELOC_KVX_NN:
+#if ARCH_SIZE == 64
+    case BFD_RELOC_KVX_32:
+#endif
+    case BFD_RELOC_KVX_S37_LO10:
+    case BFD_RELOC_KVX_S37_UP27:
+
+    case BFD_RELOC_KVX_S32_LO5:
+    case BFD_RELOC_KVX_S32_UP27:
+
+    case BFD_RELOC_KVX_S43_LO10:
+    case BFD_RELOC_KVX_S43_UP27:
+    case BFD_RELOC_KVX_S43_EX6:
+
+    case BFD_RELOC_KVX_S64_LO10:
+    case BFD_RELOC_KVX_S64_UP27:
+    case BFD_RELOC_KVX_S64_EX27:
+      /* When generating a shared object or relocatable executable, these
+         relocations are copied into the output file to be resolved at
+         run time.  */
+      if (((bfd_link_pic (info) == true)
+	    || globals->root.is_relocatable_executable)
+	  && (input_section->flags & SEC_ALLOC)
+	  && (h == NULL
+	      || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT && !resolved_to_zero)
+	      || h->root.type != bfd_link_hash_undefweak))
+	{
+	  Elf_Internal_Rela outrel;
+	  bfd_byte *loc;
+	  bool skip, relocate;
+	  asection *sreloc;
+
+	  *unresolved_reloc_p = false;
+
+	  skip = false;
+	  relocate = false;
+
+	  outrel.r_addend = signed_addend;
+	  outrel.r_offset =
+	    _bfd_elf_section_offset (output_bfd, info, input_section,
+				     rel->r_offset);
+	  if (outrel.r_offset == (bfd_vma) - 1)
+	    skip = true;
+	  else if (outrel.r_offset == (bfd_vma) - 2)
+	    {
+	      skip = true;
+	      relocate = true;
+	    }
+
+	  outrel.r_offset += (input_section->output_section->vma
+			      + input_section->output_offset);
+
+	  if (skip)
+	    memset (&outrel, 0, sizeof outrel);
+	  else if (h != NULL
+		   && h->dynindx != -1
+		   && (!bfd_link_pic (info) || !info->symbolic || !h->def_regular))
+	    outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+	  else if (bfd_r_type == BFD_RELOC_KVX_32
+		   || bfd_r_type == BFD_RELOC_KVX_64)
+	    {
+	      int symbol;
+
+	      /* On SVR4-ish systems, the dynamic loader cannot
+		 relocate the text and data segments independently,
+		 so the symbol does not matter.  */
+	      symbol = 0;
+	      outrel.r_info = ELFNN_R_INFO (symbol, R_KVX_RELATIVE);
+	      outrel.r_addend += value;
+	    }
+	  else if (bfd_link_pic (info) && info->symbolic)
+	    {
+	      goto skip_because_pic;
+	    }
+	  else
+	    {
+	      /* We may endup here from bad input code trying to
+		 insert relocation on symbols within code.  We do not
+		 want that currently, and such code should use GOT +
+		 KVX_32/64 reloc that translate in KVX_RELATIVE
+	      */
+		const char *name;
+		if (h && h->root.root.string)
+		  name = h->root.root.string;
+		else
+		  name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
+					   NULL);
+
+		(*_bfd_error_handler)
+                        /* xgettext:c-format */
+                        (_("%pB(%pA+%#" PRIx64 "): "
+                                "unresolvable %s relocation in section `%s'"),
+                                input_bfd, input_section, (uint64_t) rel->r_offset, howto->name,
+                                name);
+		return bfd_reloc_notsupported;
+	    }
+
+	  sreloc = elf_section_data (input_section)->sreloc;
+	  if (sreloc == NULL || sreloc->contents == NULL)
+	    return bfd_reloc_notsupported;
+
+	  loc = sreloc->contents + sreloc->reloc_count++ * RELOC_SIZE (globals);
+	  bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc);
+
+	  if (sreloc->reloc_count * RELOC_SIZE (globals) > sreloc->size)
+	    {
+	      /* Sanity to check that we have previously allocated
+		 sufficient space in the relocation section for the
+		 number of relocations we actually want to emit.  */
+	      abort ();
+	    }
+
+	  /* If this reloc is against an external symbol, we do not want to
+	     fiddle with the addend.  Otherwise, we need to include the symbol
+	     value so that it becomes an addend for the dynamic reloc.  */
+	  if (!relocate)
+	    return bfd_reloc_ok;
+
+	  rret = check_signed_overflow (complain_overflow_signed, bfd_r_type,
+					input_bfd, value + signed_addend);
+	  if (rret != bfd_reloc_ok)
+	    return rret;
+
+	  return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					   contents, rel->r_offset, value,
+					   signed_addend);
+	}
+
+    skip_because_pic:
+      rret = check_signed_overflow (complain_overflow_signed, bfd_r_type,
+				    input_bfd, value + signed_addend);
+      if (rret != bfd_reloc_ok)
+	return rret;
+
+      return _bfd_final_link_relocate (howto, input_bfd, input_section,
+				       contents, rel->r_offset, value,
+				       signed_addend);
+      break;
+
+    case BFD_RELOC_KVX_PCREL17:
+    case BFD_RELOC_KVX_PCREL27:
+      {
+	/*
+	 * BCU insn are always first in a bundle, so there is no need
+	 * to correct the address using offset within bundle
+	 */
+
+	asection *splt = globals->root.splt;
+	bool via_plt_p =
+	  splt != NULL && h != NULL && h->plt.offset != (bfd_vma) - 1;
+
+	/* A call to an undefined weak symbol is converted to a jump to
+	   the next instruction unless a PLT entry will be created.
+	   The jump to the next instruction is optimized as a NOP.
+	   Do the same for local undefined symbols.  */
+	if (weak_undef_p && ! via_plt_p)
+	  {
+	    bfd_putl32 (INSN_NOP, hit_data);
+	    return bfd_reloc_ok;
+	  }
+
+	/* If the call goes through a PLT entry, make sure to
+	   check distance to the right destination address.  */
+	if (via_plt_p)
+	  value = (splt->output_section->vma
+		   + splt->output_offset + h->plt.offset);
+
+	/* Check if a stub has to be inserted because the destination
+	   is too far away.  */
+	struct elf_kvx_stub_hash_entry *stub_entry = NULL;
+
+	/* If the target symbol is global and marked as a function the
+	   relocation applies a function call or a tail call.  In this
+	   situation we can veneer out of range branches.  The veneers
+	   use R16 and R17 hence cannot be used arbitrary out of range
+	   branches that occur within the body of a function.  */
+
+	/* Check if a stub has to be inserted because the destination
+	   is too far away.  */
+	if (! kvx_valid_call_p (value, place))
+	  {
+	    /* The target is out of reach, so redirect the branch to
+	       the local stub for this function.  */
+	    stub_entry = elfNN_kvx_get_stub_entry (input_section,
+						  sym_sec, h,
+						  rel, globals);
+	    if (stub_entry != NULL)
+	      value = (stub_entry->stub_offset
+		       + stub_entry->stub_sec->output_offset
+		       + stub_entry->stub_sec->output_section->vma);
+	    /* We have redirected the destination to stub entry address,
+	       so ignore any addend record in the original rela entry.  */
+	    signed_addend = 0;
+	  }
+      }
+      *unresolved_reloc_p = false;
+
+      /* FALLTHROUGH */
+
+      /* PCREL 32 are used in dwarf2 table for exception handling */
+    case BFD_RELOC_KVX_32_PCREL:
+    case BFD_RELOC_KVX_S64_PCREL_LO10:
+    case BFD_RELOC_KVX_S64_PCREL_UP27:
+    case BFD_RELOC_KVX_S64_PCREL_EX27:
+    case BFD_RELOC_KVX_S37_PCREL_LO10:
+    case BFD_RELOC_KVX_S37_PCREL_UP27:
+    case BFD_RELOC_KVX_S43_PCREL_LO10:
+    case BFD_RELOC_KVX_S43_PCREL_UP27:
+    case BFD_RELOC_KVX_S43_PCREL_EX6:
+      return _bfd_final_link_relocate (howto, input_bfd, input_section,
+				       contents, rel->r_offset, value,
+				       signed_addend);
+      break;
+
+    case BFD_RELOC_KVX_S37_TLS_LE_LO10:
+    case BFD_RELOC_KVX_S37_TLS_LE_UP27:
+
+    case BFD_RELOC_KVX_S43_TLS_LE_LO10:
+    case BFD_RELOC_KVX_S43_TLS_LE_UP27:
+    case BFD_RELOC_KVX_S43_TLS_LE_EX6:
+	return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					 contents, rel->r_offset, value - tpoff_base (info),
+					 signed_addend);
+      break;
+
+    case BFD_RELOC_KVX_S37_TLS_DTPOFF_LO10:
+    case BFD_RELOC_KVX_S37_TLS_DTPOFF_UP27:
+
+    case BFD_RELOC_KVX_S43_TLS_DTPOFF_LO10:
+    case BFD_RELOC_KVX_S43_TLS_DTPOFF_UP27:
+    case BFD_RELOC_KVX_S43_TLS_DTPOFF_EX6:
+	return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					 contents, rel->r_offset, value - dtpoff_base (info),
+					 signed_addend);
+
+    case BFD_RELOC_KVX_S37_TLS_GD_UP27:
+    case BFD_RELOC_KVX_S37_TLS_GD_LO10:
+
+    case BFD_RELOC_KVX_S43_TLS_GD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_GD_EX6:
+    case BFD_RELOC_KVX_S43_TLS_GD_LO10:
+
+    case BFD_RELOC_KVX_S37_TLS_IE_UP27:
+    case BFD_RELOC_KVX_S37_TLS_IE_LO10:
+
+    case BFD_RELOC_KVX_S43_TLS_IE_UP27:
+    case BFD_RELOC_KVX_S43_TLS_IE_EX6:
+    case BFD_RELOC_KVX_S43_TLS_IE_LO10:
+
+    case BFD_RELOC_KVX_S37_TLS_LD_UP27:
+    case BFD_RELOC_KVX_S37_TLS_LD_LO10:
+
+    case BFD_RELOC_KVX_S43_TLS_LD_UP27:
+    case BFD_RELOC_KVX_S43_TLS_LD_EX6:
+    case BFD_RELOC_KVX_S43_TLS_LD_LO10:
+
+      if (globals->root.sgot == NULL)
+    	return bfd_reloc_notsupported;
+      value = symbol_got_offset (input_bfd, h, r_symndx);
+
+      _bfd_final_link_relocate (howto, input_bfd, input_section,
+				contents, rel->r_offset, value,
+				signed_addend);
+      *unresolved_reloc_p = false;
+      break;
+
+    case BFD_RELOC_KVX_S37_GOTADDR_UP27:
+    case BFD_RELOC_KVX_S37_GOTADDR_LO10:
+
+    case BFD_RELOC_KVX_S43_GOTADDR_UP27:
+    case BFD_RELOC_KVX_S43_GOTADDR_EX6:
+    case BFD_RELOC_KVX_S43_GOTADDR_LO10:
+
+    case BFD_RELOC_KVX_S64_GOTADDR_UP27:
+    case BFD_RELOC_KVX_S64_GOTADDR_EX27:
+    case BFD_RELOC_KVX_S64_GOTADDR_LO10:
+      {
+	if (globals->root.sgot == NULL)
+	  BFD_ASSERT (h != NULL);
+
+	value = globals->root.sgot->output_section->vma
+	  + globals->root.sgot->output_offset;
+
+	return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					 contents, rel->r_offset, value,
+					 signed_addend);
+      }
+      break;
+
+    case BFD_RELOC_KVX_S37_GOTOFF_LO10:
+    case BFD_RELOC_KVX_S37_GOTOFF_UP27:
+
+    case BFD_RELOC_KVX_32_GOTOFF:
+    case BFD_RELOC_KVX_64_GOTOFF:
+
+    case BFD_RELOC_KVX_S43_GOTOFF_LO10:
+    case BFD_RELOC_KVX_S43_GOTOFF_UP27:
+    case BFD_RELOC_KVX_S43_GOTOFF_EX6:
+
+      {
+	asection *basegot = globals->root.sgot;
+	/* BFD_ASSERT(h == NULL); */
+	BFD_ASSERT(globals->root.sgot != NULL);
+	value -= basegot->output_section->vma + basegot->output_offset;
+	return _bfd_final_link_relocate (howto, input_bfd, input_section,
+					 contents, rel->r_offset, value,
+					 signed_addend);
+      }
+      break;
+
+    case BFD_RELOC_KVX_S37_GOT_LO10:
+    case BFD_RELOC_KVX_S37_GOT_UP27:
+
+    case BFD_REL[...]

[diff truncated at 100000 bytes]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-08-16 13:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-16 13:23 [binutils-gdb] kvx: New port Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).