upgraded to binutils 2.21.1
authorAndrew Waterman <waterman@s144.Millennium.Berkeley.EDU>
Thu, 3 Nov 2011 01:06:14 +0000 (18:06 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 01:28:04 +0000 (18:28 -0700)
tools/compilers/gcc-glibc/Makefile
tools/compilers/gcc-glibc/Makelocal.template
tools/compilers/gcc-glibc/binutils-2.21.1-riscv.patch [new file with mode: 0644]
tools/compilers/gcc-glibc/binutils-2.21.1-ros.patch [new file with mode: 0644]

index 880d60c..2f62491 100644 (file)
@@ -4,11 +4,11 @@ MAKE_JOBS :=
 # Defines where to install the toolchain
 -include Makelocal
 
-ifndef RAMP_INSTDIR
+ifndef RISCV_INSTDIR
 ifndef X86_INSTDIR
 busted: 
-       @echo "You need to setup either a RAMP_INSTDIR or X86_INSTDIR to point to where you want the tools installed. The best way to do this is to create a 'Makelocal' file in the current directory and put it in there."; false
-ramp: busted
+       @echo "You need to setup either a RISCV_INSTDIR or X86_INSTDIR to point to where you want the tools installed. The best way to do this is to create a 'Makelocal' file in the current directory and put it in there."; false
+riscv: busted
 x86: busted
 endif
 endif 
@@ -20,7 +20,7 @@ ifneq ($(AWK),GNU)
 $(error You need to have 'gawk' installed on your system!)
 endif
 
-BINUTILS_VERSION := 2.18
+BINUTILS_VERSION := 2.21.1
 GCC_VERSION := 4.3.2
 GLIBC_VERSION := 2.11.1
 
@@ -28,11 +28,11 @@ BUILDDIR ?= $(shell pwd)/
 ROSDIR ?= $(BUILDDIR)/../../../
 DESTDIR ?= /
 
-# Configuration parameters for make-ramp
-RAMP_ARCH := sparc
-RAMP_BINARY_PREFIX := $(RAMP_ARCH)-ros-
-RAMP_GCC_BUILD_FLAGS := --with-cpu=v8
-RAMP_CFLAGS :=
+# Configuration parameters for make-riscv
+RISCV_ARCH := riscv
+RISCV_BINARY_PREFIX := $(RISCV_ARCH)-ros-
+RISCV_GCC_BUILD_FLAGS := --with-cpu=v8
+RISCV_CFLAGS :=
 
 # Configuration parameters for x86
 X86_ARCH := i686
@@ -43,24 +43,24 @@ X86_CFLAGS := -march=i486
 all:
        @echo "You need to run one of the following commands, "
        @echo "depending on which version of the cross compiler you are trying to generate:"
-       @echo "  make ramp"
+       @echo "  make riscv"
        @echo "  make x86"
-       @echo "  make ramp-revert"
+       @echo "  make riscv-revert"
        @echo "  make x86-revert"
-       @echo "  make ramp-uninstall"
+       @echo "  make riscv-uninstall"
        @echo "  make x86-uninstall"
        @echo "  make clean"
 
-ramp:
+riscv:
        export LD_LIBRARY_PATH=; \
        export DESTDIR=$(DESTDIR);\
-       export INSTDIR=$(RAMP_INSTDIR);\
-       export PATH=$(DESTDIR)$(RAMP_INSTDIR)/bin:$(PATH);\
-       export ARCH=$(RAMP_ARCH);\
-       export ARCH_CFLAGS=$(RAMP_CFLAGS);\
-       export ROS_ARCH_DIR=$(RAMP_ARCH);\
-       export BINARY_PREFIX=$(RAMP_BINARY_PREFIX);\
-       export GCC_BUILD_FLAGS=$(RAMP_GCC_BUILD_FLAGS);\
+       export INSTDIR=$(RISCV_INSTDIR);\
+       export PATH=$(DESTDIR)$(RISCV_INSTDIR)/bin:$(PATH);\
+       export ARCH=$(RISCV_ARCH);\
+       export ARCH_CFLAGS=$(RISCV_CFLAGS);\
+       export ROS_ARCH_DIR=$(RISCV_ARCH);\
+       export BINARY_PREFIX=$(RISCV_BINARY_PREFIX);\
+       export GCC_BUILD_FLAGS=$(RISCV_GCC_BUILD_FLAGS);\
        $(MAKE) make-all
 
 x86:
@@ -91,15 +91,15 @@ make-all:
        mkdir -p $(ROSDIR)/fs/$(ARCH)/lib
        cp -r $(INSTDIR)/$(ARCH)-ros/lib/* $(ROSDIR)/fs/$(ARCH)/lib
 
-ramp-uninstall:
-       -rm -rf $(RAMP_INSTDIR)
+riscv-uninstall:
+       -rm -rf $(RISCV_INSTDIR)
 
 x86-uninstall:
        -rm -rf $(X86_INSTDIR)
 
-ramp-revert: 
-       rm -rf $(RAMP_INSTDIR)
-       cp -r $(RAMP_BINARY_PREFIX)install.bak $(RAMP_INSTDIR)
+riscv-revert:
+       rm -rf $(RISCV_INSTDIR)
+       cp -r $(RISCV_BINARY_PREFIX)install.bak $(RISCV_INSTDIR)
 
 x86-revert: 
        rm -rf $(X86_INSTDIR)
@@ -127,10 +127,14 @@ glibc-clean:
        cd $(BINARY_PREFIX)glibc-builddir; \
        make clean
 
-binutils-$(BINUTILS_VERSION):
+%.tar.bz2:
+       wget http://akaros.cs.berkeley.edu/xcc/$@
+
+binutils-$(BINUTILS_VERSION): binutils-$(BINUTILS_VERSION).tar.bz2
        rm -rf binutils-$(BINUTILS_VERSION);
-       tar -zxf binutils-$(BINUTILS_VERSION).tar.gz
+       tar -jxf binutils-$(BINUTILS_VERSION).tar.bz2
        patch -p0 < binutils-$(BINUTILS_VERSION)-ros.patch
+       patch -p0 < binutils-$(BINUTILS_VERSION)-riscv.patch
 
 gcc-$(GCC_VERSION):
        rm -rf gcc-$(GCC_VERSION)
index fa34a38..1da2e42 100644 (file)
@@ -1,3 +1,3 @@
-RAMP_INSTDIR := /scratch/klueska/ros-gcc-glibc/install-sparc-ros-gcc/
+RISCV_INSTDIR := /scratch/klueska/ros-gcc-glibc/install-sparc-ros-gcc/
 X86_INSTDIR := /scratch/klueska/ros-gcc-glibc/install-i386-ros-gcc/
 
diff --git a/tools/compilers/gcc-glibc/binutils-2.21.1-riscv.patch b/tools/compilers/gcc-glibc/binutils-2.21.1-riscv.patch
new file mode 100644 (file)
index 0000000..e274daf
--- /dev/null
@@ -0,0 +1,23848 @@
+diff -ruN binutils-2.21.1-orig/bfd/archures.c binutils-2.21.1/bfd/archures.c
+--- binutils-2.21.1-orig/bfd/archures.c        2010-07-23 07:52:46.000000000 -0700
++++ binutils-2.21.1/bfd/archures.c     2011-10-22 18:46:17.000000000 -0700
+@@ -515,6 +515,7 @@
+ extern const bfd_arch_info_type bfd_plugin_arch;
+ extern const bfd_arch_info_type bfd_powerpc_archs[];
+ #define bfd_powerpc_arch bfd_powerpc_archs[0]
++extern const bfd_arch_info_type bfd_riscv_arch;
+ extern const bfd_arch_info_type bfd_rs6000_arch;
+ extern const bfd_arch_info_type bfd_rx_arch;
+ extern const bfd_arch_info_type bfd_s390_arch;
+@@ -589,6 +590,7 @@
+     &bfd_or32_arch,
+     &bfd_pdp11_arch,
+     &bfd_powerpc_arch,
++    &bfd_riscv_arch,
+     &bfd_rs6000_arch,
+     &bfd_rx_arch,
+     &bfd_s390_arch,
+diff -ruN binutils-2.21.1-orig/bfd/bfd-in2.h binutils-2.21.1/bfd/bfd-in2.h
+--- binutils-2.21.1-orig/bfd/bfd-in2.h 2011-06-27 00:39:01.000000000 -0700
++++ binutils-2.21.1/bfd/bfd-in2.h      2011-10-22 18:46:17.000000000 -0700
+@@ -1919,6 +1919,9 @@
+ #define bfd_mach_ppc_e500mc    5001
+ #define bfd_mach_ppc_e500mc64  5005
+ #define bfd_mach_ppc_titan     83
++  bfd_arch_riscv, /* RISC-V */
++#define bfd_mach_riscv_rocket32 132
++#define bfd_mach_riscv_rocket64 164
+   bfd_arch_rs6000,    /* IBM RS/6000 */
+ #define bfd_mach_rs6k          6000
+ #define bfd_mach_rs6k_rs1      6001
+@@ -4761,6 +4764,14 @@
+ value in a word.  The relocation is relative offset from  */
+   BFD_RELOC_MICROBLAZE_32_GOTOFF,
++  /* RISC-V relocations */
++  BFD_RELOC_RISCV_TLS_GOT_HI16,
++  BFD_RELOC_RISCV_TLS_GOT_LO16,
++  BFD_RELOC_RISCV_TLS_GD_HI16,
++  BFD_RELOC_RISCV_TLS_GD_LO16,
++  BFD_RELOC_RISCV_TLS_LDM_HI16,
++  BFD_RELOC_RISCV_TLS_LDM_LO16,
++
+ /* This is used to tell the dynamic linker to copy the value out of
+ the dynamic object into the runtime process image.  */
+   BFD_RELOC_MICROBLAZE_COPY,
+diff -ruN binutils-2.21.1-orig/bfd/config.bfd binutils-2.21.1/bfd/config.bfd
+--- binutils-2.21.1-orig/bfd/config.bfd        2011-04-01 05:02:42.000000000 -0700
++++ binutils-2.21.1/bfd/config.bfd     2011-10-22 18:46:17.000000000 -0700
+@@ -96,6 +96,7 @@
+ pdp11*)                targ_archs=bfd_pdp11_arch ;;
+ pj*)           targ_archs="bfd_pj_arch bfd_i386_arch";;
+ powerpc*)      targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;;
++riscv*)                targ_archs=bfd_riscv_arch ;;
+ rs6000)                targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;;
+ s390*)                 targ_archs=bfd_s390_arch ;;
+ sh*)           targ_archs=bfd_sh_arch ;;
+@@ -1193,6 +1194,14 @@
+     targ_selvecs="bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec"
+     ;;
++#ifdef BFD64
++  riscv*-*-linux*)
++    targ_defvec=bfd_elf64_littleriscv_vec
++    targ_selvecs="bfd_elf32_littleriscv_vec bfd_elf64_littleriscv_vec"
++    want64=true
++    ;;
++#endif
++
+   rx-*-elf)
+     targ_defvec=bfd_elf32_rx_le_vec
+     targ_selvecs="bfd_elf32_rx_be_vec bfd_elf32_rx_le_vec"
+diff -ruN binutils-2.21.1-orig/bfd/configure binutils-2.21.1/bfd/configure
+--- binutils-2.21.1-orig/bfd/configure 2011-06-27 01:57:12.000000000 -0700
++++ binutils-2.21.1/bfd/configure      2011-10-22 18:47:51.000000000 -0700
+@@ -15239,6 +15239,7 @@
+     bfd_elf32_littlemips_vec)         tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_littlemips_vxworks_vec)
+                               tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
++    bfd_elf32_littleriscv_vec)        tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;;
+     bfd_elf32_m32r_vec)               tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
+     bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
+@@ -15320,6 +15321,7 @@
+     bfd_elf64_ia64_vms_vec)   tb="$tb elf64-ia64.lo elf64.lo vms-lib.lo vms-misc.lo $elf"; target_size=64 ;;
+     bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
+     bfd_elf64_littlemips_vec)         tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
++    bfd_elf64_littleriscv_vec)        tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+     bfd_elf64_mmix_vec)       tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;;
+     bfd_elf64_powerpc_vec)    tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
+     bfd_elf64_powerpcle_vec)  tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;;
+diff -ruN binutils-2.21.1-orig/bfd/configure.in binutils-2.21.1/bfd/configure.in
+--- binutils-2.21.1-orig/bfd/configure.in      2011-06-27 01:57:10.000000000 -0700
++++ binutils-2.21.1/bfd/configure.in   2011-10-22 18:46:17.000000000 -0700
+@@ -730,6 +730,7 @@
+     bfd_elf32_littlemips_vec)         tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_littlemips_vxworks_vec)
+                               tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;;
++    bfd_elf32_littleriscv_vec)        tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo" ;;
+     bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;;
+     bfd_elf32_m32r_vec)               tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
+     bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;;
+@@ -811,6 +812,7 @@
+     bfd_elf64_ia64_vms_vec)   tb="$tb elf64-ia64.lo elf64.lo vms-lib.lo vms-misc.lo $elf"; target_size=64 ;;
+     bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
+     bfd_elf64_littlemips_vec)         tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
++    bfd_elf64_littleriscv_vec)        tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
+     bfd_elf64_mmix_vec)       tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;;
+     bfd_elf64_powerpc_vec)    tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
+     bfd_elf64_powerpcle_vec)  tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;;
+diff -ruN binutils-2.21.1-orig/bfd/cpu-riscv.c binutils-2.21.1/bfd/cpu-riscv.c
+--- binutils-2.21.1-orig/bfd/cpu-riscv.c       1969-12-31 16:00:00.000000000 -0800
++++ binutils-2.21.1/bfd/cpu-riscv.c    2011-10-22 18:50:03.000000000 -0700
+@@ -0,0 +1,78 @@
++/* bfd back-end for mips support
++   Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001,
++   2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
++   Written by Steve Chamberlain of Cygnus Support.
++
++   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; if not, write to the Free Software
++   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
++   MA 02110-1301, USA.  */
++
++#include "sysdep.h"
++#include "bfd.h"
++#include "libbfd.h"
++
++static const bfd_arch_info_type *mips_compatible
++  (const bfd_arch_info_type *, const bfd_arch_info_type *);
++
++/* The default routine tests bits_per_word, which is wrong on mips as
++   mips word size doesn't correlate with reloc size.  */
++
++static const bfd_arch_info_type *
++mips_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b)
++{
++  if (a->arch != b->arch)
++    return NULL;
++
++  /* Machine compatibility is checked in
++     _bfd_mips_elf_merge_private_bfd_data.  */
++
++  return a;
++}
++
++#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT)         \
++  {                                                   \
++    BITS_WORD, /*  bits in a word */                  \
++    BITS_ADDR, /* bits in an address */                       \
++    8,        /* 8 bits in a byte */                          \
++    bfd_arch_riscv,                                   \
++    NUMBER,                                           \
++    "riscv",                                          \
++    PRINT,                                            \
++    3,                                                        \
++    DEFAULT,                                          \
++    mips_compatible,                                  \
++    bfd_default_scan,                                 \
++    NEXT,                                             \
++  }
++
++enum
++{
++  I_riscv_rocket64,
++  I_riscv_rocket32
++};
++
++#define NN(index) (&arch_info_struct[(index) + 1])
++
++static const bfd_arch_info_type arch_info_struct[] =
++{
++  N (64, 64, bfd_mach_riscv_rocket64, "riscv:rocket64", FALSE, NN(I_riscv_rocket64)),
++  N (32, 32, bfd_mach_riscv_rocket32, "riscv:rocket32", FALSE, 0)
++};
++
++/* The default architecture is riscv:rocket64. */
++
++const bfd_arch_info_type bfd_riscv_arch =
++N (64, 64, 0, "riscv", TRUE, &arch_info_struct[0]);
+diff -ruN binutils-2.21.1-orig/bfd/elf32-riscv.c binutils-2.21.1/bfd/elf32-riscv.c
+--- binutils-2.21.1-orig/bfd/elf32-riscv.c     1969-12-31 16:00:00.000000000 -0800
++++ binutils-2.21.1/bfd/elf32-riscv.c  2011-10-22 18:50:03.000000000 -0700
+@@ -0,0 +1,2300 @@
++/* MIPS-specific support for 32-bit ELF
++   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
++   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
++
++   Most of the information added by Ian Lance Taylor, Cygnus Support,
++   <ian@cygnus.com>.
++   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
++   <mark@codesourcery.com>
++   Traditional MIPS targets support added by Koundinya.K, Dansk Data
++   Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
++
++   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; if not, write to the Free Software
++   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
++   MA 02110-1301, USA.  */
++
++
++/* This file handles MIPS ELF targets.  SGI Irix 5 uses a slightly
++   different MIPS ELF from other targets.  This matters when linking.
++   This file supports both, switching at runtime.  */
++
++#include "sysdep.h"
++#include "bfd.h"
++#include "libbfd.h"
++#include "bfdlink.h"
++#include "genlink.h"
++#include "elf-bfd.h"
++#include "elfxx-riscv.h"
++#include "elf/riscv.h"
++#include "opcode/riscv.h"
++
++/* Get the ECOFF swapping routines.  */
++#include "coff/sym.h"
++#include "coff/symconst.h"
++#include "coff/internal.h"
++#include "coff/ecoff.h"
++#include "coff/mips.h"
++#define ECOFF_SIGNED_32
++#include "ecoffswap.h"
++
++#include "opcode/riscv.h"
++
++static bfd_boolean mips_elf_assign_gp
++  (bfd *, bfd_vma *);
++static bfd_reloc_status_type mips_elf_final_gp
++  (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
++static bfd_reloc_status_type mips_elf_gprel16_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type mips_elf_literal_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type mips_elf_gprel32_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type gprel32_with_gp
++  (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma);
++static bfd_reloc_status_type mips16_gprel_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
++  (bfd *, bfd_reloc_code_real_type);
++static reloc_howto_type *mips_elf_n32_rtype_to_howto
++  (unsigned int, bfd_boolean);
++static void mips_info_to_howto_rel
++  (bfd *, arelent *, Elf_Internal_Rela *);
++static void mips_info_to_howto_rela
++  (bfd *, arelent *, Elf_Internal_Rela *);
++static bfd_boolean mips_elf_sym_is_global
++  (bfd *, asymbol *);
++static bfd_boolean mips_elf_n32_object_p
++  (bfd *);
++static bfd_boolean elf32_mips_grok_prstatus
++  (bfd *, Elf_Internal_Note *);
++static bfd_boolean elf32_mips_grok_psinfo
++  (bfd *, Elf_Internal_Note *);
++
++extern const bfd_target bfd_elf32_nbigmips_vec;
++extern const bfd_target bfd_elf32_nlittlemips_vec;
++
++/* Nonzero if ABFD is using the N32 ABI.  */
++#define ABI_N32_P(abfd) \
++  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
++
++/* The number of local .got entries we reserve.  */
++#define MIPS_RESERVED_GOTNO (2)
++
++/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
++   from smaller values.  Start with zero, widen, *then* decrement.  */
++#define MINUS_ONE     (((bfd_vma)0) - 1)
++
++/* The relocation table used for SHT_REL sections.  */
++
++static reloc_howto_type elf_mips_howto_table_rel[] =
++{
++  /* No relocation.  */
++  HOWTO (R_RISCV_NONE,                /* type */
++       0,                     /* rightshift */
++       0,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_NONE",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (1),
++
++  /* 32 bit relocation.  */
++  HOWTO (R_RISCV_32,          /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_32",          /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit symbol relative relocation.  */
++  HOWTO (R_RISCV_REL32,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL32",       /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 26 bit jump address.  */
++  HOWTO (R_RISCV_26,          /* type */
++       RISCV_JUMP_ALIGN_BITS,                 /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_JUMP_BITS,                       /* bitsize */
++       TRUE,                  /* pc_relative */
++       OP_SH_TARGET,                  /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper 36
++                                 bits must match the PC + 4.  */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_26",          /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* src_mask */
++       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* dst_mask */
++       TRUE),         /* pcrel_offset */
++
++  /* R_RISCV_HI16 and R_RISCV_LO16 are unsupported for NewABI REL.
++     However, the native IRIX6 tools use them, so we try our best. */
++
++  /* High 16 bits of symbol value.  */
++  HOWTO (R_RISCV_HI16,                /* type */
++       RISCV_IMM_BITS,                        /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32-RISCV_IMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,                    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_RISCV_HI16",                /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<(32-RISCV_IMM_BITS))-1) << OP_SH_BIGIMMEDIATE,            /* src_mask */
++       ((1<<(32-RISCV_IMM_BITS))-1) << OP_SH_BIGIMMEDIATE,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of symbol value.  */
++  HOWTO (R_RISCV_LO16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,                       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_RISCV_LO16",                /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* GP relative reference.  */
++  HOWTO (R_RISCV_GPREL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf_gprel16_reloc, /* special_function */
++       "R_RISCV_GPREL16",     /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to literal section.  */
++  HOWTO (R_RISCV_LITERAL,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf_literal_reloc, /* special_function */
++       "R_RISCV_LITERAL",     /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to global offset table.  */
++  HOWTO (R_RISCV_GOT16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_RISCV_GOT16",       /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 16 bit PC relative reference.  Note that the ABI document has a typo
++     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless.
++     We do the right thing here.  */
++  HOWTO (R_RISCV_PC16,                /* type */
++       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_PC16",                /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       TRUE),                 /* pcrel_offset */
++
++  /* 16 bit call through global offset table.  */
++  HOWTO (R_RISCV_CALL16,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL16",      /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit GP relative reference.  */
++  HOWTO (R_RISCV_GPREL32,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       mips_elf_gprel32_reloc, /* special_function */
++       "R_RISCV_GPREL32",     /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (13),
++  EMPTY_HOWTO (14),
++  EMPTY_HOWTO (15),
++  EMPTY_HOWTO (16),
++  EMPTY_HOWTO (17),
++
++  /* 64 bit relocation.  */
++  HOWTO (R_RISCV_64,          /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_64",          /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Displacement in the global offset table.  */
++  HOWTO (R_RISCV_GOT_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_DISP",    /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (20),
++  EMPTY_HOWTO (21),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_HI16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32-RISCV_IMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_HI16",    /* name */
++       TRUE,                  /* partial_inplace */
++       (1<<(RISCV_IMM_BITS))-1,               /* src_mask */
++       (1<<(RISCV_IMM_BITS))-1,               /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_LO16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_LO16",    /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 64 bit subtraction.  */
++  HOWTO (R_RISCV_SUB,         /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SUB",         /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_A,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_A",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction, and change all relocations
++     to refer to the old instruction at the address.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_B,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_B",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Delete a 32 bit instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_DELETE,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_DELETE",      /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (28),
++  EMPTY_HOWTO (29),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_HI16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32-RISCV_IMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_HI16",   /* name */
++       TRUE,                  /* partial_inplace */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* src_mask */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_LO16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_LO16",   /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Section displacement, used by an associated event location section.  */
++  HOWTO (R_RISCV_SCN_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SCN_DISP",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_REL16,               /* type */
++       0,                     /* rightshift */
++       1,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL16",       /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* These two are obsolete.  */
++  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE),
++  EMPTY_HOWTO (R_RISCV_PJUMP),
++
++  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section.
++     It must be used for multigot GOT's (and only there).  */
++  HOWTO (R_RISCV_RELGOT,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_RELGOT",      /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Protected jump conversion.  This is an optimization hint.  No
++     relocation is required for correctness.  */
++  HOWTO (R_RISCV_JALR,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_JALR",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x00000000,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS relocations.  */
++  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD32),
++  EMPTY_HOWTO (R_RISCV_TLS_DTPREL32),
++
++  HOWTO (R_RISCV_TLS_DTPMOD64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPMOD64",        /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_TLS_DTPREL64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL64",        /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS general dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_GD,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GD",      /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_LDM,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_LDM",     /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_HI16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32-RISCV_IMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_HI16",     /* name */
++       TRUE,                  /* partial_inplace */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* src_mask */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_LO16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_LO16",     /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GOTTPREL,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GOTTPREL",        /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS IE dynamic relocations.  */
++  EMPTY_HOWTO (R_RISCV_TLS_TPREL32),
++
++  HOWTO (R_RISCV_TLS_TPREL64, /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL64", /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_HI16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32-RISCV_IMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_HI16", /* name */
++       TRUE,                  /* partial_inplace */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* src_mask */
++       (1<<(32-RISCV_IMM_BITS))-1,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_LO16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_LO16", /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_IMM_REACH-1,             /* src_mask */
++       RISCV_IMM_REACH-1,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit relocation with no addend.  */
++  HOWTO (R_RISCV_GLOB_DAT,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GLOB_DAT",    /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++/* The relocation table used for SHT_RELA sections.  */
++
++static reloc_howto_type elf_mips_howto_table_rela[] =
++{
++  /* No relocation.  */
++  HOWTO (R_RISCV_NONE,                /* type */
++       0,                     /* rightshift */
++       0,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_NONE",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (1),
++
++  /* 32 bit relocation.  */
++  HOWTO (R_RISCV_32,          /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_32",          /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit symbol relative relocation.  */
++  HOWTO (R_RISCV_REL32,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_REL32",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 26 bit jump address.  */
++  HOWTO (R_RISCV_26,          /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       26,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper 36
++                                 bits must match the PC + 4.  */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_26",          /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x03ffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of symbol value.  */
++  HOWTO (R_RISCV_HI16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_HI16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of symbol value.  */
++  HOWTO (R_RISCV_LO16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_LO16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* GP relative reference.  */
++  HOWTO (R_RISCV_GPREL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf_gprel16_reloc, /* special_function */
++       "R_RISCV_GPREL16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to literal section.  */
++  HOWTO (R_RISCV_LITERAL,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf_literal_reloc, /* special_function */
++       "R_RISCV_LITERAL",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to global offset table.  */
++  HOWTO (R_RISCV_GOT16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GOT16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 16 bit PC relative reference.  Note that the ABI document has a typo
++     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless.
++     We do the right thing here.  */
++  HOWTO (R_RISCV_PC16,                /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_PC16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       TRUE),                 /* pcrel_offset */
++
++  /* 16 bit call through global offset table.  */
++  HOWTO (R_RISCV_CALL16,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_CALL16",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit GP relative reference.  */
++  HOWTO (R_RISCV_GPREL32,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       mips_elf_gprel32_reloc, /* special_function */
++       "R_RISCV_GPREL32",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (13),
++  EMPTY_HOWTO (14),
++  EMPTY_HOWTO (15),
++  EMPTY_HOWTO (16),
++  EMPTY_HOWTO (17),
++
++  /* 64 bit relocation.  */
++  HOWTO (R_RISCV_64,          /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_64",          /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Displacement in the global offset table.  */
++  HOWTO (R_RISCV_GOT_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GOT_DISP",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (20),
++  EMPTY_HOWTO (21),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_HI16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GOT_HI16",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_LO16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GOT_LO16",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 64 bit subtraction.  */
++  HOWTO (R_RISCV_SUB,         /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_SUB",         /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_A,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_INSERT_A",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction, and change all relocations
++     to refer to the old instruction at the address.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_B,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_INSERT_B",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Delete a 32 bit instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_DELETE,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_DELETE",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (28),
++  EMPTY_HOWTO (29),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_HI16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_CALL_HI16",   /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_LO16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_CALL_LO16",   /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Section displacement, used by an associated event location section.  */
++  HOWTO (R_RISCV_SCN_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_SCN_DISP",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 16 bit relocation.  */
++  HOWTO (R_RISCV_REL16,               /* type */
++       0,                     /* rightshift */
++       1,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_REL16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffff,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* These two are obsolete.  */
++  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE),
++  EMPTY_HOWTO (R_RISCV_PJUMP),
++
++  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section.
++     It must be used for multigot GOT's (and only there).  */
++  HOWTO (R_RISCV_RELGOT,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_RELGOT",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Protected jump conversion.  This is an optimization hint.  No
++     relocation is required for correctness.  */
++  HOWTO (R_RISCV_JALR,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_JALR",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS GD/LD dynamic relocations.  */
++  HOWTO (R_RISCV_TLS_DTPMOD32,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPMOD32",        /* name */
++       FALSE,                 /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_TLS_DTPREL32,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL32",        /* name */
++       FALSE,                 /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD64),
++  EMPTY_HOWTO (R_RISCV_TLS_DTPREL64),
++
++  /* TLS general dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_GD,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GD",      /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_LDM,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_LDM",     /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_HI16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_HI16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_LO16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_LO16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GOTTPREL,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GOTTPREL",        /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS IE dynamic relocations.  */
++  HOWTO (R_RISCV_TLS_TPREL32, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL32", /* name */
++       FALSE,                 /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (R_RISCV_TLS_TPREL64),
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_HI16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_HI16", /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_LO16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_LO16", /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit relocation with no addend.  */
++  HOWTO (R_RISCV_GLOB_DAT,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GLOB_DAT",    /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++static reloc_howto_type elf_mips16_howto_table_rel[] =
++{
++  /* The reloc used for the mips16 jump instruction.  */
++  HOWTO (R_MIPS16_26,         /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       26,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper four
++                                 bits must match the PC.  */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_26",         /* name */
++       TRUE,                  /* partial_inplace */
++       0x3ffffff,             /* src_mask */
++       0x3ffffff,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* The reloc used for the mips16 gprel instruction.  */
++  HOWTO (R_MIPS16_GPREL,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips16_gprel_reloc,    /* special_function */
++       "R_MIPS16_GPREL",      /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 reference to the global offset table.  */
++  HOWTO (R_MIPS16_GOT16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_MIPS16_GOT16",      /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 call through the global offset table.  */
++  HOWTO (R_MIPS16_CALL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_CALL16",     /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 high 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_HI16,               /* type */
++       16,                    /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_MIPS16_HI16",       /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 low 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_LO16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_MIPS16_LO16",       /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++static reloc_howto_type elf_mips16_howto_table_rela[] =
++{
++  /* The reloc used for the mips16 jump instruction.  */
++  HOWTO (R_MIPS16_26,         /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       26,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper four
++                                 bits must match the PC.  */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_26",         /* name */
++       FALSE,                 /* partial_inplace */
++       0x3ffffff,             /* src_mask */
++       0x3ffffff,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* The reloc used for the mips16 gprel instruction.  */
++  HOWTO (R_MIPS16_GPREL,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips16_gprel_reloc,    /* special_function */
++       "R_MIPS16_GPREL",      /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 reference to the global offset table.  */
++  HOWTO (R_MIPS16_GOT16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_MIPS16_GOT16",      /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 call through the global offset table.  */
++  HOWTO (R_MIPS16_CALL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_CALL16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 high 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_HI16,               /* type */
++       16,                    /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_MIPS16_HI16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 low 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_LO16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_MIPS16_LO16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++/* GNU extension to record C++ vtable hierarchy */
++static reloc_howto_type elf_mips_gnu_vtinherit_howto =
++  HOWTO (R_RISCV_GNU_VTINHERIT,       /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       NULL,                  /* special_function */
++       "R_RISCV_GNU_VTINHERIT", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++/* GNU extension to record C++ vtable member usage */
++static reloc_howto_type elf_mips_gnu_vtentry_howto =
++  HOWTO (R_RISCV_GNU_VTENTRY, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_elf_rel_vtable_reloc_fn, /* special_function */
++       "R_RISCV_GNU_VTENTRY", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++\f
++/* 16 bit offset for pc-relative branches.  */
++static reloc_howto_type elf_mips_gnu_rel16_s2 =
++  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GNU_REL16_S2",        /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       TRUE);                 /* pcrel_offset */
++
++/* 16 bit offset for pc-relative branches.  */
++static reloc_howto_type elf_mips_gnu_rela16_s2 =
++  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GNU_REL16_S2",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       TRUE);                 /* pcrel_offset */
++\f
++/* Originally a VxWorks extension, but now used for other systems too.  */
++static reloc_howto_type elf_mips_copy_howto =
++  HOWTO (R_RISCV_COPY,                /* type */
++       0,                     /* rightshift */
++       0,                     /* this one is variable size */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_bitfield, /* complain_on_overflow */
++       bfd_elf_generic_reloc, /* special_function */
++       "R_RISCV_COPY",                /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0x0,                   /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++/* Originally a VxWorks extension, but now used for other systems too.  */
++static reloc_howto_type elf_mips_jump_slot_howto =
++  HOWTO (R_RISCV_JUMP_SLOT,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_bitfield, /* complain_on_overflow */
++       bfd_elf_generic_reloc, /* special_function */
++       "R_RISCV_JUMP_SLOT",   /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0x0,                   /* dst_mask */
++       FALSE);                /* pcrel_offset */
++\f
++/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
++   dangerous relocation.  */
++
++static bfd_boolean
++mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
++{
++  unsigned int count;
++  asymbol **sym;
++  unsigned int i;
++
++  /* If we've already figured out what GP will be, just return it.  */
++  *pgp = _bfd_get_gp_value (output_bfd);
++  if (*pgp)
++    return TRUE;
++
++  count = bfd_get_symcount (output_bfd);
++  sym = bfd_get_outsymbols (output_bfd);
++
++  /* The linker script will have created a symbol named `_gp' with the
++     appropriate value.  */
++  if (sym == NULL)
++    i = count;
++  else
++    {
++      for (i = 0; i < count; i++, sym++)
++      {
++        register const char *name;
++
++        name = bfd_asymbol_name (*sym);
++        if (*name == '_' && strcmp (name, "_gp") == 0)
++          {
++            *pgp = bfd_asymbol_value (*sym);
++            _bfd_set_gp_value (output_bfd, *pgp);
++            break;
++          }
++      }
++    }
++
++  if (i >= count)
++    {
++      /* Only get the error once.  */
++      *pgp = 4;
++      _bfd_set_gp_value (output_bfd, *pgp);
++      return FALSE;
++    }
++
++  return TRUE;
++}
++
++/* We have to figure out the gp value, so that we can adjust the
++   symbol value correctly.  We look up the symbol _gp in the output
++   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
++   target data.  We don't need to adjust the symbol value for an
++   external symbol if we are producing relocatable output.  */
++
++static bfd_reloc_status_type
++mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
++                 char **error_message, bfd_vma *pgp)
++{
++  if (bfd_is_und_section (symbol->section)
++      && ! relocatable)
++    {
++      *pgp = 0;
++      return bfd_reloc_undefined;
++    }
++
++  *pgp = _bfd_get_gp_value (output_bfd);
++  if (*pgp == 0
++      && (! relocatable
++        || (symbol->flags & BSF_SECTION_SYM) != 0))
++    {
++      if (relocatable)
++      {
++        /* Make up a value.  */
++        *pgp = symbol->section->output_section->vma /*+ 0x4000*/;
++        _bfd_set_gp_value (output_bfd, *pgp);
++      }
++      else if (!mips_elf_assign_gp (output_bfd, pgp))
++      {
++        *error_message =
++          (char *) _("GP relative relocation when _gp not defined");
++        return bfd_reloc_dangerous;
++      }
++    }
++
++  return bfd_reloc_ok;
++}
++
++/* Do a R_RISCV_GPREL16 relocation.  This is a 16 bit value which must
++   become the offset from the gp register.  */
++
++static bfd_reloc_status_type
++mips_elf_gprel16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
++                      asymbol *symbol, void *data ATTRIBUTE_UNUSED,
++                      asection *input_section, bfd *output_bfd,
++                      char **error_message ATTRIBUTE_UNUSED)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
++                         &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                      input_section, relocatable,
++                                      data, gp);
++}
++
++/* Do a R_RISCV_LITERAL relocation.  */
++
++static bfd_reloc_status_type
++mips_elf_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                      void *data, asection *input_section, bfd *output_bfd,
++                      char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++
++  /* R_RISCV_LITERAL relocations are defined for local symbols only.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      *error_message = (char *)
++      _("literal relocation occurs for an external symbol");
++      return bfd_reloc_outofrange;
++    }
++
++  /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.  */
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
++                         &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                      input_section, relocatable,
++                                      data, gp);
++}
++
++/* Do a R_RISCV_GPREL32 relocation.  This is a 32 bit value which must
++   become the offset from the gp register.  */
++
++static bfd_reloc_status_type
++mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                      void *data, asection *input_section, bfd *output_bfd,
++                      char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++
++  /* R_RISCV_GPREL32 relocations are defined for local symbols only.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      *error_message = (char *)
++      _("32bits gp relative relocation occurs for an external symbol");
++      return bfd_reloc_outofrange;
++    }
++
++  if (output_bfd != NULL)
++    {
++      relocatable = TRUE;
++      gp = _bfd_get_gp_value (output_bfd);
++    }
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++
++      ret = mips_elf_final_gp (output_bfd, symbol, relocatable,
++                             error_message, &gp);
++      if (ret != bfd_reloc_ok)
++      return ret;
++    }
++
++  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
++                        relocatable, data, gp);
++}
++
++static bfd_reloc_status_type
++gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
++               asection *input_section, bfd_boolean relocatable,
++               void *data, bfd_vma gp)
++{
++  bfd_vma relocation;
++  unsigned long val;
++
++  if (bfd_is_com_section (symbol->section))
++    relocation = 0;
++  else
++    relocation = symbol->value;
++
++  relocation += symbol->section->output_section->vma;
++  relocation += symbol->section->output_offset;
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  if (reloc_entry->howto->src_mask == 0)
++    val = 0;
++  else
++    val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
++
++  /* Set val to the offset into the section or symbol.  */
++  val += reloc_entry->addend;
++
++  /* Adjust val for the final section location and GP value.  If we
++     are producing relocatable output, we don't want to do this for
++     an external symbol.  */
++  if (! relocatable
++      || (symbol->flags & BSF_SECTION_SYM) != 0)
++    val += relocation - gp;
++
++  bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
++
++  if (relocatable)
++    reloc_entry->address += input_section->output_offset;
++
++  return bfd_reloc_ok;
++}
++
++/* Handle a mips16 GP relative reloc.  */
++
++static bfd_reloc_status_type
++mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                  void *data, asection *input_section, bfd *output_bfd,
++                  char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_byte *location;
++  bfd_vma gp;
++
++  /* If we're relocating, and this is an external symbol, we don't want
++     to change anything.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      reloc_entry->address += input_section->output_offset;
++      return bfd_reloc_ok;
++    }
++
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
++                         &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  location = (bfd_byte *) data + reloc_entry->address;
++  ret = _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                     input_section, relocatable,
++                                     data, gp);
++
++  return ret;
++}
++\f
++/* A mapping from BFD reloc types to MIPS ELF reloc types.  */
++
++struct elf_reloc_map {
++  bfd_reloc_code_real_type bfd_val;
++  enum elf_riscv_reloc_type elf_val;
++};
++
++static const struct elf_reloc_map mips_reloc_map[] =
++{
++  { BFD_RELOC_NONE, R_RISCV_NONE },
++  { BFD_RELOC_32, R_RISCV_32 },
++  /* There is no BFD reloc for R_RISCV_REL32.  */
++  { BFD_RELOC_CTOR, R_RISCV_32 },
++  { BFD_RELOC_64, R_RISCV_64 },
++  { BFD_RELOC_16_PCREL_S2, R_RISCV_PC16 },
++  { BFD_RELOC_HI16_S, R_RISCV_HI16 },
++  { BFD_RELOC_LO16, R_RISCV_LO16 },
++  { BFD_RELOC_GPREL16, R_RISCV_GPREL16 },
++  { BFD_RELOC_GPREL32, R_RISCV_GPREL32 },
++  { BFD_RELOC_MIPS_JMP, R_RISCV_26 },
++  { BFD_RELOC_MIPS_LITERAL, R_RISCV_LITERAL },
++  { BFD_RELOC_MIPS_GOT16, R_RISCV_GOT16 },
++  { BFD_RELOC_MIPS_CALL16, R_RISCV_CALL16 },
++  { BFD_RELOC_MIPS_GOT_DISP, R_RISCV_GOT_DISP },
++  { BFD_RELOC_MIPS_GOT_HI16, R_RISCV_GOT_HI16 },
++  { BFD_RELOC_MIPS_GOT_LO16, R_RISCV_GOT_LO16 },
++  { BFD_RELOC_MIPS_SUB, R_RISCV_SUB },
++  { BFD_RELOC_MIPS_INSERT_A, R_RISCV_INSERT_A },
++  { BFD_RELOC_MIPS_INSERT_B, R_RISCV_INSERT_B },
++  { BFD_RELOC_MIPS_DELETE, R_RISCV_DELETE },
++  { BFD_RELOC_MIPS_CALL_HI16, R_RISCV_CALL_HI16 },
++  { BFD_RELOC_MIPS_CALL_LO16, R_RISCV_CALL_LO16 },
++  { BFD_RELOC_MIPS_SCN_DISP, R_RISCV_SCN_DISP },
++  { BFD_RELOC_MIPS_REL16, R_RISCV_REL16 },
++  /* Use of R_RISCV_ADD_IMMEDIATE and R_RISCV_PJUMP is deprecated.  */
++  { BFD_RELOC_MIPS_RELGOT, R_RISCV_RELGOT },
++  { BFD_RELOC_MIPS_JALR, R_RISCV_JALR },
++  { BFD_RELOC_MIPS_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
++  { BFD_RELOC_MIPS_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
++  { BFD_RELOC_MIPS_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
++  { BFD_RELOC_MIPS_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
++  { BFD_RELOC_MIPS_TLS_GD, R_RISCV_TLS_GD },
++  { BFD_RELOC_MIPS_TLS_LDM, R_RISCV_TLS_LDM },
++  { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_RISCV_TLS_DTPREL_HI16 },
++  { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_RISCV_TLS_DTPREL_LO16 },
++  { BFD_RELOC_MIPS_TLS_GOTTPREL, R_RISCV_TLS_GOTTPREL },
++  { BFD_RELOC_MIPS_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
++  { BFD_RELOC_MIPS_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
++  { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_RISCV_TLS_TPREL_HI16 },
++  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_RISCV_TLS_TPREL_LO16 }
++};
++
++static const struct elf_reloc_map mips16_reloc_map[] =
++{
++  { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
++};
++
++/* Given a BFD reloc type, return a howto structure.  */
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++                               bfd_reloc_code_real_type code)
++{
++  unsigned int i;
++  /* FIXME: We default to RELA here instead of choosing the right
++     relocation variant.  */
++  reloc_howto_type *howto_table = elf_mips_howto_table_rela;
++  reloc_howto_type *howto16_table = elf_mips16_howto_table_rela;
++
++  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
++       i++)
++    {
++      if (mips_reloc_map[i].bfd_val == code)
++      return &howto_table[(int) mips_reloc_map[i].elf_val];
++    }
++
++  for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
++       i++)
++    {
++      if (mips16_reloc_map[i].bfd_val == code)
++      return &howto16_table[(int) mips16_reloc_map[i].elf_val];
++    }
++
++  switch (code)
++    {
++    case BFD_RELOC_VTABLE_INHERIT:
++      return &elf_mips_gnu_vtinherit_howto;
++    case BFD_RELOC_VTABLE_ENTRY:
++      return &elf_mips_gnu_vtentry_howto;
++    case BFD_RELOC_MIPS_COPY:
++      return &elf_mips_copy_howto;
++    case BFD_RELOC_MIPS_JUMP_SLOT:
++      return &elf_mips_jump_slot_howto;
++    default:
++      bfd_set_error (bfd_error_bad_value);
++      return NULL;
++    }
++}
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++                               const char *r_name)
++{
++  unsigned int i;
++
++  for (i = 0;
++       i < (sizeof (elf_mips_howto_table_rela)
++          / sizeof (elf_mips_howto_table_rela[0]));
++       i++)
++    if (elf_mips_howto_table_rela[i].name != NULL
++      && strcasecmp (elf_mips_howto_table_rela[i].name, r_name) == 0)
++      return &elf_mips_howto_table_rela[i];
++
++  for (i = 0;
++       i < (sizeof (elf_mips16_howto_table_rela)
++          / sizeof (elf_mips16_howto_table_rela[0]));
++       i++)
++    if (elf_mips16_howto_table_rela[i].name != NULL
++      && strcasecmp (elf_mips16_howto_table_rela[i].name, r_name) == 0)
++      return &elf_mips16_howto_table_rela[i];
++
++  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
++    return &elf_mips_gnu_vtinherit_howto;
++  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0)
++    return &elf_mips_gnu_vtentry_howto;
++  if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0)
++    return &elf_mips_gnu_rel16_s2;
++  if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0)
++    return &elf_mips_gnu_rela16_s2;
++  if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0)
++    return &elf_mips_copy_howto;
++  if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0)
++    return &elf_mips_jump_slot_howto;
++
++  return NULL;
++}
++
++/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
++
++static reloc_howto_type *
++mips_elf_n32_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p)
++{
++  switch (r_type)
++    {
++    case R_RISCV_GNU_VTINHERIT:
++      return &elf_mips_gnu_vtinherit_howto;
++    case R_RISCV_GNU_VTENTRY:
++      return &elf_mips_gnu_vtentry_howto;
++    case R_RISCV_GNU_REL16_S2:
++      if (rela_p)
++      return &elf_mips_gnu_rela16_s2;
++      else
++      return &elf_mips_gnu_rel16_s2;
++    case R_RISCV_COPY:
++      return &elf_mips_copy_howto;
++    case R_RISCV_JUMP_SLOT:
++      return &elf_mips_jump_slot_howto;
++    default:
++      if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
++      {
++        if (rela_p)
++          return &elf_mips16_howto_table_rela[r_type - R_MIPS16_min];
++        else
++          return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min];
++      }
++      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max);
++      if (rela_p)
++      return &elf_mips_howto_table_rela[r_type];
++      else
++      return &elf_mips_howto_table_rel[r_type];
++      break;
++    }
++}
++
++/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
++
++static void
++mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
++{
++  unsigned int r_type;
++
++  r_type = ELF32_R_TYPE (dst->r_info);
++  cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, FALSE);
++
++  /* The addend for a GPREL16 or LITERAL relocation comes from the GP
++     value for the object file.  We get the addend now, rather than
++     when we do the relocation, because the symbol manipulations done
++     by the linker may cause us to lose track of the input BFD.  */
++  if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
++      && (r_type == R_RISCV_GPREL16 || r_type == (unsigned int) R_RISCV_LITERAL))
++    cache_ptr->addend = elf_gp (abfd);
++}
++
++/* Given a MIPS Elf_Internal_Rela, fill in an arelent structure.  */
++
++static void
++mips_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
++                       arelent *cache_ptr, Elf_Internal_Rela *dst)
++{
++  unsigned int r_type;
++
++  r_type = ELF32_R_TYPE (dst->r_info);
++  cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, TRUE);
++  cache_ptr->addend = dst->r_addend;
++}
++\f
++/* Determine whether a symbol is global for the purposes of splitting
++   the symbol table into global symbols and local symbols.  At least
++   on Irix 5, this split must be between section symbols and all other
++   symbols.  On most ELF targets the split is between static symbols
++   and externally visible symbols.  */
++
++static bfd_boolean
++mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
++{
++  return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
++        || bfd_is_und_section (bfd_get_section (sym))
++        || bfd_is_com_section (bfd_get_section (sym)));
++}
++\f
++/* Set the right machine number for a MIPS ELF file.  */
++
++static bfd_boolean
++mips_elf_n32_object_p (bfd *abfd)
++{
++  unsigned long mach;
++
++  mach = _bfd_elf_riscv_mach (elf_elfheader (abfd)->e_flags);
++  bfd_default_set_arch_mach (abfd, bfd_arch_riscv, mach);
++
++  if (! ABI_N32_P(abfd))
++    return FALSE;
++
++  return TRUE;
++}
++\f
++/* Support for core dump NOTE sections.  */
++static bfd_boolean
++elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
++{
++  int offset;
++  unsigned int size;
++
++  switch (note->descsz)
++    {
++      default:
++      return FALSE;
++
++      case 440:               /* Linux/MIPS N32 */
++      /* pr_cursig */
++      elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
++
++      /* pr_pid */
++      elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
++
++      /* pr_reg */
++      offset = 72;
++      size = 360;
++
++      break;
++    }
++
++  /* Make a ".reg/999" section.  */
++  return _bfd_elfcore_make_pseudosection (abfd, ".reg", size,
++                                        note->descpos + offset);
++}
++
++static bfd_boolean
++elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
++{
++  switch (note->descsz)
++    {
++      default:
++      return FALSE;
++
++      case 128:               /* Linux/MIPS elf_prpsinfo */
++      elf_tdata (abfd)->core_program
++       = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
++      elf_tdata (abfd)->core_command
++       = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
++    }
++
++  /* Note that for some reason, a spurious space is tacked
++     onto the end of the args in some (at least one anyway)
++     implementations, so strip it off if it exists.  */
++
++  {
++    char *command = elf_tdata (abfd)->core_command;
++    int n = strlen (command);
++
++    if (0 < n && command[n - 1] == ' ')
++      command[n - 1] = '\0';
++  }
++
++  return TRUE;
++}
++
++/* ECOFF swapping routines.  These are used when dealing with the
++   .mdebug section, which is in the ECOFF debugging format.  */
++static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
++  /* Symbol table magic number.  */
++  magicSym,
++  /* Alignment of debugging information.  E.g., 4.  */
++  4,
++  /* Sizes of external symbolic information.  */
++  sizeof (struct hdr_ext),
++  sizeof (struct dnr_ext),
++  sizeof (struct pdr_ext),
++  sizeof (struct sym_ext),
++  sizeof (struct opt_ext),
++  sizeof (struct fdr_ext),
++  sizeof (struct rfd_ext),
++  sizeof (struct ext_ext),
++  /* Functions to swap in external symbolic data.  */
++  ecoff_swap_hdr_in,
++  ecoff_swap_dnr_in,
++  ecoff_swap_pdr_in,
++  ecoff_swap_sym_in,
++  ecoff_swap_opt_in,
++  ecoff_swap_fdr_in,
++  ecoff_swap_rfd_in,
++  ecoff_swap_ext_in,
++  _bfd_ecoff_swap_tir_in,
++  _bfd_ecoff_swap_rndx_in,
++  /* Functions to swap out external symbolic data.  */
++  ecoff_swap_hdr_out,
++  ecoff_swap_dnr_out,
++  ecoff_swap_pdr_out,
++  ecoff_swap_sym_out,
++  ecoff_swap_opt_out,
++  ecoff_swap_fdr_out,
++  ecoff_swap_rfd_out,
++  ecoff_swap_ext_out,
++  _bfd_ecoff_swap_tir_out,
++  _bfd_ecoff_swap_rndx_out,
++  /* Function to read in symbolic data.  */
++  _bfd_riscv_elf_read_ecoff_info
++};
++\f
++#define ELF_ARCH                      bfd_arch_riscv
++#define ELF_TARGET_ID                 MIPS_ELF_DATA
++#define ELF_MACHINE_CODE              EM_RISCV
++
++#define elf_backend_collect           TRUE
++#define elf_backend_type_change_ok    TRUE
++#define elf_backend_can_gc_sections   TRUE
++#define elf_info_to_howto             mips_info_to_howto_rela
++#define elf_info_to_howto_rel         mips_info_to_howto_rel
++#define elf_backend_sym_is_global     mips_elf_sym_is_global
++#define elf_backend_object_p          mips_elf_n32_object_p
++#define elf_backend_symbol_processing _bfd_riscv_elf_symbol_processing
++#define elf_backend_section_processing        _bfd_riscv_elf_section_processing
++#define elf_backend_section_from_shdr _bfd_riscv_elf_section_from_shdr
++#define elf_backend_fake_sections     _bfd_riscv_elf_fake_sections
++#define elf_backend_section_from_bfd_section \
++                                      _bfd_riscv_elf_section_from_bfd_section
++#define elf_backend_add_symbol_hook   _bfd_riscv_elf_add_symbol_hook
++#define elf_backend_link_output_symbol_hook \
++                                      _bfd_riscv_elf_link_output_symbol_hook
++#define elf_backend_create_dynamic_sections \
++                                      _bfd_riscv_elf_create_dynamic_sections
++#define elf_backend_check_relocs      _bfd_riscv_elf_check_relocs
++#define elf_backend_merge_symbol_attribute \
++                                      _bfd_riscv_elf_merge_symbol_attribute
++#define elf_backend_get_target_dtag   _bfd_riscv_elf_get_target_dtag
++#define elf_backend_adjust_dynamic_symbol \
++                                      _bfd_riscv_elf_adjust_dynamic_symbol
++#define elf_backend_always_size_sections \
++                                      _bfd_riscv_elf_always_size_sections
++#define elf_backend_size_dynamic_sections \
++                                      _bfd_riscv_elf_size_dynamic_sections
++#define elf_backend_init_index_section        _bfd_elf_init_1_index_section
++#define elf_backend_relocate_section  _bfd_riscv_elf_relocate_section
++#define elf_backend_finish_dynamic_symbol \
++                                      _bfd_riscv_elf_finish_dynamic_symbol
++#define elf_backend_finish_dynamic_sections \
++                                      _bfd_riscv_elf_finish_dynamic_sections
++#define elf_backend_final_write_processing \
++                                      _bfd_riscv_elf_final_write_processing
++#define elf_backend_additional_program_headers \
++                                      _bfd_riscv_elf_additional_program_headers
++#define elf_backend_modify_segment_map        _bfd_riscv_elf_modify_segment_map
++#define elf_backend_gc_mark_hook      _bfd_riscv_elf_gc_mark_hook
++#define elf_backend_gc_sweep_hook     _bfd_riscv_elf_gc_sweep_hook
++#define elf_backend_copy_indirect_symbol \
++                                      _bfd_riscv_elf_copy_indirect_symbol
++#define elf_backend_grok_prstatus     elf32_mips_grok_prstatus
++#define elf_backend_grok_psinfo               elf32_mips_grok_psinfo
++#define elf_backend_ecoff_debug_swap  &mips_elf32_ecoff_debug_swap
++
++#define elf_backend_got_header_size   (4 * MIPS_RESERVED_GOTNO)
++
++/* MIPS n32 ELF can use a mixture of REL and RELA, but some Relocations
++   work better/work only in RELA, so we default to this.  */
++#define elf_backend_may_use_rel_p     1
++#define elf_backend_may_use_rela_p    1
++#define elf_backend_default_use_rela_p        1
++#define elf_backend_rela_plts_and_copies_p 0
++#define elf_backend_sign_extend_vma   TRUE
++#define elf_backend_plt_readonly      1
++#define elf_backend_plt_sym_val               _bfd_riscv_elf_plt_sym_val
++
++#define elf_backend_discard_info      _bfd_riscv_elf_discard_info
++#define elf_backend_ignore_discarded_relocs \
++                                      _bfd_riscv_elf_ignore_discarded_relocs
++#define elf_backend_write_section     _bfd_riscv_elf_write_section
++#define elf_backend_mips_rtype_to_howto       mips_elf_n32_rtype_to_howto
++#define bfd_elf32_find_nearest_line   _bfd_riscv_elf_find_nearest_line
++#define bfd_elf32_find_inliner_info   _bfd_riscv_elf_find_inliner_info
++#define bfd_elf32_new_section_hook    _bfd_riscv_elf_new_section_hook
++#define bfd_elf32_set_section_contents        _bfd_riscv_elf_set_section_contents
++#define bfd_elf32_bfd_get_relocated_section_contents \
++                              _bfd_elf_riscv_get_relocated_section_contents
++#define bfd_elf32_bfd_link_hash_table_create \
++                                      _bfd_riscv_elf_link_hash_table_create
++#define bfd_elf32_bfd_final_link      _bfd_riscv_elf_final_link
++#define bfd_elf32_bfd_merge_private_bfd_data \
++                                      _bfd_riscv_elf_merge_private_bfd_data
++#define bfd_elf32_bfd_set_private_flags       _bfd_riscv_elf_set_private_flags
++#define bfd_elf32_bfd_print_private_bfd_data \
++                                      _bfd_riscv_elf_print_private_bfd_data
++#define bfd_elf32_bfd_relax_section     _bfd_riscv_relax_section
++
++/* Support for SGI-ish mips targets using n32 ABI.  */
++
++#define TARGET_LITTLE_SYM               bfd_elf32_littleriscv_vec
++#define TARGET_LITTLE_NAME              "elf32-littleriscv"
++#define TARGET_BIG_SYM                  bfd_elf32_bigriscv_vec
++#define TARGET_BIG_NAME                 "elf32-bigriscv"
++
++#define ELF_MAXPAGESIZE                       0x10000
++#define ELF_COMMONPAGESIZE            0x1000
++
++#include "elf32-target.h"
+diff -ruN binutils-2.21.1-orig/bfd/elf64-riscv.c binutils-2.21.1/bfd/elf64-riscv.c
+--- binutils-2.21.1-orig/bfd/elf64-riscv.c     1969-12-31 16:00:00.000000000 -0800
++++ binutils-2.21.1/bfd/elf64-riscv.c  2011-10-22 18:50:03.000000000 -0700
+@@ -0,0 +1,3298 @@
++/* MIPS-specific support for 64-bit ELF
++   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
++   2006, 2007, 2008, 2009, 2010
++   Free Software Foundation, Inc.
++   Ian Lance Taylor, Cygnus Support
++   Linker support added by Mark Mitchell, CodeSourcery, LLC.
++   <mark@codesourcery.com>
++
++   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; if not, write to the Free Software
++   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
++   MA 02110-1301, USA.  */
++
++
++/* This file supports the 64-bit MIPS ELF ABI.
++
++   The MIPS 64-bit ELF ABI uses an unusual reloc format.  This file
++   overrides the usual ELF reloc handling, and handles reading and
++   writing the relocations here.  */
++
++/* TODO: Many things are unsupported, even if there is some code for it
++ .       (which was mostly stolen from elf32-mips.c and slightly adapted).
++ .
++ .   - Relocation handling for REL relocs is wrong in many cases and
++ .     generally untested.
++ .   - Relocation handling for RELA relocs related to GOT support are
++ .     also likely to be wrong.
++ .   - Support for MIPS16 is untested.
++ .   - Combined relocs with RSS_* entries are unsupported.
++ .   - The whole GOT handling for NewABI is missing, some parts of
++ .     the OldABI version is still lying around and should be removed.
++ */
++
++#include "sysdep.h"
++#include "bfd.h"
++#include "libbfd.h"
++#include "aout/ar.h"
++#include "bfdlink.h"
++#include "genlink.h"
++#include "elf-bfd.h"
++#include "elfxx-riscv.h"
++#include "elf/riscv.h"
++#include "opcode/riscv.h"
++
++/* Get the ECOFF swapping routines.  The 64-bit ABI is not supposed to
++   use ECOFF.  However, we support it anyhow for an easier changeover.  */
++#include "coff/sym.h"
++#include "coff/symconst.h"
++#include "coff/internal.h"
++#include "coff/ecoff.h"
++/* The 64 bit versions of the mdebug data structures are in alpha.h.  */
++#include "coff/alpha.h"
++#define ECOFF_SIGNED_64
++#include "ecoffswap.h"
++
++#include "opcode/riscv.h"
++
++static void mips_elf64_swap_reloc_in
++  (bfd *, const Elf64_Mips_External_Rel *, Elf64_Mips_Internal_Rela *);
++static void mips_elf64_swap_reloca_in
++  (bfd *, const Elf64_Mips_External_Rela *, Elf64_Mips_Internal_Rela *);
++static void mips_elf64_swap_reloc_out
++  (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rel *);
++static void mips_elf64_swap_reloca_out
++  (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rela *);
++static void mips_elf64_be_swap_reloc_in
++  (bfd *, const bfd_byte *, Elf_Internal_Rela *);
++static void mips_elf64_be_swap_reloc_out
++  (bfd *, const Elf_Internal_Rela *, bfd_byte *);
++static void mips_elf64_be_swap_reloca_in
++  (bfd *, const bfd_byte *, Elf_Internal_Rela *);
++static void mips_elf64_be_swap_reloca_out
++  (bfd *, const Elf_Internal_Rela *, bfd_byte *);
++static reloc_howto_type *bfd_elf64_bfd_reloc_type_lookup
++  (bfd *, bfd_reloc_code_real_type);
++static reloc_howto_type *mips_elf64_rtype_to_howto
++  (unsigned int, bfd_boolean);
++static void mips_elf64_info_to_howto_rel
++  (bfd *, arelent *, Elf_Internal_Rela *);
++static void mips_elf64_info_to_howto_rela
++  (bfd *, arelent *, Elf_Internal_Rela *);
++static long mips_elf64_get_reloc_upper_bound
++  (bfd *, asection *);
++static long mips_elf64_canonicalize_reloc
++  (bfd *, asection *, arelent **, asymbol **);
++static long mips_elf64_get_dynamic_reloc_upper_bound
++  (bfd *);
++static long mips_elf64_canonicalize_dynamic_reloc
++  (bfd *, arelent **, asymbol **);
++static bfd_boolean mips_elf64_slurp_one_reloc_table
++  (bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type, arelent *,
++   asymbol **, bfd_boolean);
++static bfd_boolean mips_elf64_slurp_reloc_table
++  (bfd *, asection *, asymbol **, bfd_boolean);
++static void mips_elf64_write_relocs
++  (bfd *, asection *, void *);
++static void mips_elf64_write_rel
++  (bfd *, asection *, Elf_Internal_Shdr *, int *, void *);
++static void mips_elf64_write_rela
++  (bfd *, asection *, Elf_Internal_Shdr *, int *, void *);
++static bfd_reloc_status_type mips_elf64_gprel16_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type mips_elf64_literal_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type mips_elf64_gprel32_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_reloc_status_type mips16_gprel_reloc
++  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
++static bfd_boolean mips_elf64_assign_gp
++  (bfd *, bfd_vma *);
++static bfd_reloc_status_type mips_elf64_final_gp
++  (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
++static bfd_boolean mips_elf64_object_p
++  (bfd *);
++static bfd_boolean elf64_mips_grok_prstatus
++  (bfd *, Elf_Internal_Note *);
++static bfd_boolean elf64_mips_grok_psinfo
++  (bfd *, Elf_Internal_Note *);
++
++/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
++   from smaller values.  Start with zero, widen, *then* decrement.  */
++#define MINUS_ONE     (((bfd_vma)0) - 1)
++
++/* The number of local .got entries we reserve.  */
++#define MIPS_RESERVED_GOTNO (2)
++\f
++/* The relocation table used for SHT_REL sections.  */
++
++static reloc_howto_type mips_elf64_howto_table_rel[] =
++{
++  /* No relocation.  */
++  HOWTO (R_RISCV_NONE,                /* type */
++       0,                     /* rightshift */
++       0,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_NONE",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (1),
++
++  /* 32 bit relocation.  */
++  HOWTO (R_RISCV_32,          /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_32",          /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit symbol relative relocation.  */
++  HOWTO (R_RISCV_REL32,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL32",       /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 26 bit jump address.  */
++  HOWTO (R_RISCV_26,          /* type */
++       RISCV_JUMP_ALIGN_BITS,                 /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_JUMP_BITS,                       /* bitsize */
++       TRUE,                  /* pc_relative */
++       OP_SH_TARGET,                  /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper 36
++                                 bits must match the PC + 4.  */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_26",          /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* src_mask */
++       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* dst_mask */
++       TRUE),         /* pcrel_offset */
++
++  /* R_RISCV_HI16 and R_RISCV_LO16 are unsupported for NewABI REL.
++     However, the native IRIX6 tools use them, so we try our best. */
++
++  /* High 16 bits of symbol value.  */
++  HOWTO (R_RISCV_HI16,                /* type */
++       RISCV_IMM_BITS,                        /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,                    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_RISCV_HI16",                /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of symbol value.  */
++  HOWTO (R_RISCV_LO16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,                       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_RISCV_LO16",                /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* GP relative reference.  */
++  HOWTO (R_RISCV_GPREL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf64_gprel16_reloc, /* special_function */
++       "R_RISCV_GPREL16",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to literal section.  */
++  HOWTO (R_RISCV_LITERAL,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf64_literal_reloc, /* special_function */
++       "R_RISCV_LITERAL",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to global offset table.  */
++  HOWTO (R_RISCV_GOT16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_RISCV_GOT16",       /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 16 bit PC relative reference.  Note that the ABI document has a typo
++     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless.
++     We do the right thing here.  */
++  HOWTO (R_RISCV_PC16,                /* type */
++       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       TRUE,                  /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_PC16",                /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       TRUE),                 /* pcrel_offset */
++
++  /* 16 bit call through global offset table.  */
++  HOWTO (R_RISCV_CALL16,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL16",      /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit GP relative reference.  */
++  HOWTO (R_RISCV_GPREL32,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       mips_elf64_gprel32_reloc, /* special_function */
++       "R_RISCV_GPREL32",     /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (13),
++  EMPTY_HOWTO (14),
++  EMPTY_HOWTO (15),
++  EMPTY_HOWTO (16),
++  EMPTY_HOWTO (17),
++
++  /* 64 bit relocation.  */
++  HOWTO (R_RISCV_64,          /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_64",          /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Displacement in the global offset table.  */
++  HOWTO (R_RISCV_GOT_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,                       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_DISP",    /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (20),
++  EMPTY_HOWTO (21),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_HI16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_HI16",    /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_LO16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_LO16",    /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 64 bit subtraction.  */
++  HOWTO (R_RISCV_SUB,         /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SUB",         /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_A,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_A",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction, and change all relocations
++     to refer to the old instruction at the address.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_B,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_B",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Delete a 32 bit instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_DELETE,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_DELETE",      /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (28),
++  EMPTY_HOWTO (29),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_HI16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_HI16",   /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_LO16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_LO16",   /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Section displacement, used by an associated event location section.  */
++  HOWTO (R_RISCV_SCN_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SCN_DISP",    /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_REL16,               /* type */
++       0,                     /* rightshift */
++       1,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL16",       /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* These two are obsolete.  */
++  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE),
++  EMPTY_HOWTO (R_RISCV_PJUMP),
++
++  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section.
++     It must be used for multigot GOT's (and only there).  */
++  HOWTO (R_RISCV_RELGOT,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_RELGOT",      /* name */
++       TRUE,                  /* partial_inplace */
++       0xffffffff,            /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Protected jump conversion.  This is an optimization hint.  No
++     relocation is required for correctness.  */
++  HOWTO (R_RISCV_JALR,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_JALR",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x00000000,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS relocations.  */
++  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD32),
++  EMPTY_HOWTO (R_RISCV_TLS_DTPREL32),
++
++  HOWTO (R_RISCV_TLS_DTPMOD64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPMOD64",        /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_TLS_DTPREL64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL64",        /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS general dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_GD,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GD",      /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_LDM,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_LDM",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_HI16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_HI16",     /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_LO16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_LO16",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GOTTPREL,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GOTTPREL",        /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS IE dynamic relocations.  */
++  EMPTY_HOWTO (R_RISCV_TLS_TPREL32),
++
++  HOWTO (R_RISCV_TLS_TPREL64, /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL64", /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_HI16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_HI16", /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_LO16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_LO16", /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GOT_HI16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GOT_HI16",        /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GOT_LO16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GOT_LO16",        /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GD_HI16, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GD_HI16", /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GD_LO16, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GD_LO16", /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_LDM_HI16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_LDM_HI16",        /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_LDM_LO16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_LDM_LO16",        /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit relocation with no addend.  */
++  HOWTO (R_RISCV_GLOB_DAT,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GLOB_DAT",    /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++/* The relocation table used for SHT_RELA sections.  */
++
++static reloc_howto_type mips_elf64_howto_table_rela[] =
++{
++  /* No relocation.  */
++  HOWTO (R_RISCV_NONE,                /* type */
++       0,                     /* rightshift */
++       0,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_NONE",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (1),
++
++  /* 32 bit relocation.  */
++  HOWTO (R_RISCV_32,          /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_32",          /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit symbol relative relocation.  */
++  HOWTO (R_RISCV_REL32,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL32",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 26 bit jump address.  */
++  HOWTO (R_RISCV_26,          /* type */
++       RISCV_JUMP_ALIGN_BITS,                 /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_JUMP_BITS,                       /* bitsize */
++       TRUE,                  /* pc_relative */
++       OP_SH_TARGET,                  /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper 36
++                                 bits must match the PC + 4.  */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_26",          /* name */
++       TRUE,                  /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* dst_mask */
++       TRUE),         /* pcrel_offset */
++
++  /* High 16 bits of symbol value.  */
++  HOWTO (R_RISCV_HI16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_HI16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,              /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of symbol value.  */
++  HOWTO (R_RISCV_LO16,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_LO16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,                /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* GP relative reference.  */
++  HOWTO (R_RISCV_GPREL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf64_gprel16_reloc, /* special_function */
++       "R_RISCV_GPREL16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to literal section.  */
++  HOWTO (R_RISCV_LITERAL,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips_elf64_literal_reloc, /* special_function */
++       "R_RISCV_LITERAL",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Reference to global offset table.  */
++  HOWTO (R_RISCV_GOT16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GOT16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 16 bit PC relative reference.  Note that the ABI document has a typo
++     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless.
++     We do the right thing here.  */
++  HOWTO (R_RISCV_PC16,                /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       TRUE,                  /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_PC16",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       TRUE),                 /* pcrel_offset */
++
++  /* 16 bit call through global offset table.  */
++  HOWTO (R_RISCV_CALL16,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL16",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit GP relative reference.  */
++  HOWTO (R_RISCV_GPREL32,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       mips_elf64_gprel32_reloc, /* special_function */
++       "R_RISCV_GPREL32",     /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (13),
++  EMPTY_HOWTO (14),
++  EMPTY_HOWTO (15),
++  EMPTY_HOWTO (16),
++  EMPTY_HOWTO (17),
++
++  /* 64 bit relocation.  */
++  HOWTO (R_RISCV_64,          /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_64",          /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Displacement in the global offset table.  */
++  HOWTO (R_RISCV_GOT_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_DISP",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (20),
++  EMPTY_HOWTO (21),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_HI16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_HI16",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_GOT_LO16,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GOT_LO16",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 64 bit subtraction.  */
++  HOWTO (R_RISCV_SUB,         /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SUB",         /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_A,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_A",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Insert the addend as an instruction, and change all relocations
++     to refer to the old instruction at the address.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_INSERT_B,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_INSERT_B",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Delete a 32 bit instruction.  */
++  /* FIXME: Not handled correctly.  */
++  HOWTO (R_RISCV_DELETE,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_DELETE",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (28),
++  EMPTY_HOWTO (29),
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_HI16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_HI16",   /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_CALL_LO16,   /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_CALL_LO16",   /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Section displacement, used by an associated event location section.  */
++  HOWTO (R_RISCV_SCN_DISP,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_SCN_DISP",    /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_REL16,               /* type */
++       0,                     /* rightshift */
++       1,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_REL16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* These two are obsolete.  */
++  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE),
++  EMPTY_HOWTO (R_RISCV_PJUMP),
++
++  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section.
++     It must be used for multigot GOT's (and only there).  */
++  HOWTO (R_RISCV_RELGOT,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_RELGOT",      /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Protected jump conversion.  This is an optimization hint.  No
++     relocation is required for correctness.  */
++  HOWTO (R_RISCV_JALR,                /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_JALR",                /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0x00000000,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS relocations.  */
++  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD32),
++  EMPTY_HOWTO (R_RISCV_TLS_DTPREL32),
++
++  HOWTO (R_RISCV_TLS_DTPMOD64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPMOD64", /* name */
++       FALSE,                 /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  HOWTO (R_RISCV_TLS_DTPREL64,        /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL64",        /* name */
++       TRUE,                  /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS general dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_GD,              /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GD",      /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic variable reference.  */
++  HOWTO (R_RISCV_TLS_LDM,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_LDM",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_HI16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_HI16",     /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS local dynamic offset.  */
++  HOWTO (R_RISCV_TLS_DTPREL_LO16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_DTPREL_LO16",     /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_GOTTPREL,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_GOTTPREL",        /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  EMPTY_HOWTO (R_RISCV_TLS_TPREL32),
++
++  HOWTO (R_RISCV_TLS_TPREL64, /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL64", /* name */
++       FALSE,                 /* partial_inplace */
++       MINUS_ONE,             /* src_mask */
++       MINUS_ONE,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_HI16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_HI16", /* name */
++       TRUE,                  /* partial_inplace */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* TLS thread pointer offset.  */
++  HOWTO (R_RISCV_TLS_TPREL_LO16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_TLS_TPREL_LO16", /* name */
++       TRUE,                  /* partial_inplace */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GOT_HI16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GOT_HI16",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GOT_LO16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GOT_LO16",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GD_HI16, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GD_HI16", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_GD_LO16, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_GD_LO16", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* High 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_LDM_HI16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BIGIMM_BITS,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_BIGIMMEDIATE,    /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_LDM_HI16",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,      /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* Low 16 bits of displacement in global offset table.  */
++  HOWTO (R_RISCV_TLS_LDM_LO16,        /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_IMM_BITS,                        /* bitsize */
++       FALSE,                 /* pc_relative */
++       OP_SH_IMMEDIATE,       /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_TLS_LDM_LO16",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,        /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* 32 bit relocation with no addend.  */
++  HOWTO (R_RISCV_GLOB_DAT,    /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       32,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GLOB_DAT",    /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0xffffffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++static reloc_howto_type mips16_elf64_howto_table_rel[] =
++{
++  /* The reloc used for the mips16 jump instruction.  */
++  HOWTO (R_MIPS16_26,         /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       26,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper four
++                                 bits must match the PC.  */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_26",         /* name */
++       TRUE,                  /* partial_inplace */
++       0x3ffffff,             /* src_mask */
++       0x3ffffff,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* The reloc used for the mips16 gprel instruction.  */
++  HOWTO (R_MIPS16_GPREL,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips16_gprel_reloc,    /* special_function */
++       "R_MIPS16_GPREL",      /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 reference to the global offset table.  */
++  HOWTO (R_MIPS16_GOT16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_MIPS16_GOT16",      /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 call through the global offset table.  */
++  HOWTO (R_MIPS16_CALL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_CALL16",     /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 high 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_HI16,               /* type */
++       16,                    /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_MIPS16_HI16",       /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 low 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_LO16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_MIPS16_LO16",       /* name */
++       TRUE,                  /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++static reloc_howto_type mips16_elf64_howto_table_rela[] =
++{
++  /* The reloc used for the mips16 jump instruction.  */
++  HOWTO (R_MIPS16_26,         /* type */
++       2,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       26,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++                              /* This needs complex overflow
++                                 detection, because the upper four
++                                 bits must match the PC.  */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_26",         /* name */
++       FALSE,                 /* partial_inplace */
++       0x3ffffff,             /* src_mask */
++       0x3ffffff,             /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* The reloc used for the mips16 gprel instruction.  */
++  HOWTO (R_MIPS16_GPREL,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       mips16_gprel_reloc,    /* special_function */
++       "R_MIPS16_GPREL",      /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 reference to the global offset table.  */
++  HOWTO (R_MIPS16_GOT16,      /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_got16_reloc, /* special_function */
++       "R_MIPS16_GOT16",      /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* A MIPS16 call through the global offset table.  */
++  HOWTO (R_MIPS16_CALL16,     /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_MIPS16_CALL16",     /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 high 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_HI16,               /* type */
++       16,                    /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_hi16_reloc, /* special_function */
++       "R_MIPS16_HI16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++
++  /* MIPS16 low 16 bits of symbol value.  */
++  HOWTO (R_MIPS16_LO16,               /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       16,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_riscv_elf_lo16_reloc, /* special_function */
++       "R_MIPS16_LO16",       /* name */
++       FALSE,                 /* partial_inplace */
++       0x0000ffff,            /* src_mask */
++       0x0000ffff,            /* dst_mask */
++       FALSE),                /* pcrel_offset */
++};
++
++/* GNU extension to record C++ vtable hierarchy */
++static reloc_howto_type elf_mips_gnu_vtinherit_howto =
++  HOWTO (R_RISCV_GNU_VTINHERIT,       /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       NULL,                  /* special_function */
++       "R_RISCV_GNU_VTINHERIT", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++/* GNU extension to record C++ vtable member usage */
++static reloc_howto_type elf_mips_gnu_vtentry_howto =
++  HOWTO (R_RISCV_GNU_VTENTRY, /* type */
++       0,                     /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_elf_rel_vtable_reloc_fn, /* special_function */
++       "R_RISCV_GNU_VTENTRY", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++\f
++/* 16 bit offset for pc-relative branches.  */
++static reloc_howto_type elf_mips_gnu_rel16_s2 =
++  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
++       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BRANCH_BITS,                     /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GNU_REL16_S2",        /* name */
++       TRUE,                  /* partial_inplace */
++       RISCV_BRANCH_REACH-1,          /* src_mask */
++       RISCV_BRANCH_REACH-1,          /* dst_mask */
++       TRUE);                 /* pcrel_offset */
++
++/* 16 bit offset for pc-relative branches.  */
++static reloc_howto_type elf_mips_gnu_rela16_s2 =
++  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
++       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BRANCH_BITS,                     /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_signed, /* complain_on_overflow */
++       _bfd_riscv_elf_generic_reloc,  /* special_function */
++       "R_RISCV_GNU_REL16_S2",        /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       RISCV_BRANCH_REACH-1,          /* dst_mask */
++       TRUE);                 /* pcrel_offset */
++\f
++/* Originally a VxWorks extension, but now used for other systems too.  */
++static reloc_howto_type elf_mips_copy_howto =
++  HOWTO (R_RISCV_COPY,                /* type */
++       0,                     /* rightshift */
++       0,                     /* this one is variable size */
++       0,                     /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_bitfield, /* complain_on_overflow */
++       bfd_elf_generic_reloc, /* special_function */
++       "R_RISCV_COPY",                /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0x0,                   /* dst_mask */
++       FALSE);                /* pcrel_offset */
++
++/* Originally a VxWorks extension, but now used for other systems too.  */
++static reloc_howto_type elf_mips_jump_slot_howto =
++  HOWTO (R_RISCV_JUMP_SLOT,   /* type */
++       0,                     /* rightshift */
++       4,                     /* size (0 = byte, 1 = short, 2 = long) */
++       64,                    /* bitsize */
++       FALSE,                 /* pc_relative */
++       0,                     /* bitpos */
++       complain_overflow_bitfield, /* complain_on_overflow */
++       bfd_elf_generic_reloc, /* special_function */
++       "R_RISCV_JUMP_SLOT",   /* name */
++       FALSE,                 /* partial_inplace */
++       0x0,                   /* src_mask */
++       0x0,                   /* dst_mask */
++       FALSE);                /* pcrel_offset */
++\f
++/* Swap in a MIPS 64-bit Rel reloc.  */
++
++static void
++mips_elf64_swap_reloc_in (bfd *abfd, const Elf64_Mips_External_Rel *src,
++                        Elf64_Mips_Internal_Rela *dst)
++{
++  dst->r_offset = H_GET_64 (abfd, src->r_offset);
++  dst->r_sym = H_GET_32 (abfd, src->r_sym);
++  dst->r_ssym = H_GET_8 (abfd, src->r_ssym);
++  dst->r_type3 = H_GET_8 (abfd, src->r_type3);
++  dst->r_type2 = H_GET_8 (abfd, src->r_type2);
++  dst->r_type = H_GET_8 (abfd, src->r_type);
++  dst->r_addend = 0;
++}
++
++/* Swap in a MIPS 64-bit Rela reloc.  */
++
++static void
++mips_elf64_swap_reloca_in (bfd *abfd, const Elf64_Mips_External_Rela *src,
++                         Elf64_Mips_Internal_Rela *dst)
++{
++  dst->r_offset = H_GET_64 (abfd, src->r_offset);
++  dst->r_sym = H_GET_32 (abfd, src->r_sym);
++  dst->r_ssym = H_GET_8 (abfd, src->r_ssym);
++  dst->r_type3 = H_GET_8 (abfd, src->r_type3);
++  dst->r_type2 = H_GET_8 (abfd, src->r_type2);
++  dst->r_type = H_GET_8 (abfd, src->r_type);
++  dst->r_addend = H_GET_S64 (abfd, src->r_addend);
++}
++
++/* Swap out a MIPS 64-bit Rel reloc.  */
++
++static void
++mips_elf64_swap_reloc_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src,
++                         Elf64_Mips_External_Rel *dst)
++{
++  H_PUT_64 (abfd, src->r_offset, dst->r_offset);
++  H_PUT_32 (abfd, src->r_sym, dst->r_sym);
++  H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
++  H_PUT_8 (abfd, src->r_type3, dst->r_type3);
++  H_PUT_8 (abfd, src->r_type2, dst->r_type2);
++  H_PUT_8 (abfd, src->r_type, dst->r_type);
++}
++
++/* Swap out a MIPS 64-bit Rela reloc.  */
++
++static void
++mips_elf64_swap_reloca_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src,
++                          Elf64_Mips_External_Rela *dst)
++{
++  H_PUT_64 (abfd, src->r_offset, dst->r_offset);
++  H_PUT_32 (abfd, src->r_sym, dst->r_sym);
++  H_PUT_8 (abfd, src->r_ssym, dst->r_ssym);
++  H_PUT_8 (abfd, src->r_type3, dst->r_type3);
++  H_PUT_8 (abfd, src->r_type2, dst->r_type2);
++  H_PUT_8 (abfd, src->r_type, dst->r_type);
++  H_PUT_S64 (abfd, src->r_addend, dst->r_addend);
++}
++
++/* Swap in a MIPS 64-bit Rel reloc.  */
++
++static void
++mips_elf64_be_swap_reloc_in (bfd *abfd, const bfd_byte *src,
++                           Elf_Internal_Rela *dst)
++{
++  Elf64_Mips_Internal_Rela mirel;
++
++  mips_elf64_swap_reloc_in (abfd,
++                          (const Elf64_Mips_External_Rel *) src,
++                          &mirel);
++
++  dst[0].r_offset = mirel.r_offset;
++  dst[0].r_info = ELF64_R_INFO (mirel.r_sym, mirel.r_type);
++  dst[0].r_addend = 0;
++  dst[1].r_offset = mirel.r_offset;
++  dst[1].r_info = ELF64_R_INFO (mirel.r_ssym, mirel.r_type2);
++  dst[1].r_addend = 0;
++  dst[2].r_offset = mirel.r_offset;
++  dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirel.r_type3);
++  dst[2].r_addend = 0;
++}
++
++/* Swap in a MIPS 64-bit Rela reloc.  */
++
++static void
++mips_elf64_be_swap_reloca_in (bfd *abfd, const bfd_byte *src,
++                            Elf_Internal_Rela *dst)
++{
++  Elf64_Mips_Internal_Rela mirela;
++
++  mips_elf64_swap_reloca_in (abfd,
++                           (const Elf64_Mips_External_Rela *) src,
++                           &mirela);
++
++  dst[0].r_offset = mirela.r_offset;
++  dst[0].r_info = ELF64_R_INFO (mirela.r_sym, mirela.r_type);
++  dst[0].r_addend = mirela.r_addend;
++  dst[1].r_offset = mirela.r_offset;
++  dst[1].r_info = ELF64_R_INFO (mirela.r_ssym, mirela.r_type2);
++  dst[1].r_addend = 0;
++  dst[2].r_offset = mirela.r_offset;
++  dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirela.r_type3);
++  dst[2].r_addend = 0;
++}
++
++/* Swap out a MIPS 64-bit Rel reloc.  */
++
++static void
++mips_elf64_be_swap_reloc_out (bfd *abfd, const Elf_Internal_Rela *src,
++                            bfd_byte *dst)
++{
++  Elf64_Mips_Internal_Rela mirel;
++
++  mirel.r_offset = src[0].r_offset;
++  BFD_ASSERT(src[0].r_offset == src[1].r_offset);
++
++  mirel.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
++  mirel.r_sym = ELF64_R_SYM (src[0].r_info);
++  mirel.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info);
++  mirel.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
++  mirel.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info);
++
++  mips_elf64_swap_reloc_out (abfd, &mirel,
++                           (Elf64_Mips_External_Rel *) dst);
++}
++
++/* Swap out a MIPS 64-bit Rela reloc.  */
++
++static void
++mips_elf64_be_swap_reloca_out (bfd *abfd, const Elf_Internal_Rela *src,
++                             bfd_byte *dst)
++{
++  Elf64_Mips_Internal_Rela mirela;
++
++  mirela.r_offset = src[0].r_offset;
++  BFD_ASSERT(src[0].r_offset == src[1].r_offset);
++  BFD_ASSERT(src[0].r_offset == src[2].r_offset);
++
++  mirela.r_type = ELF64_MIPS_R_TYPE (src[0].r_info);
++  mirela.r_sym = ELF64_R_SYM (src[0].r_info);
++  mirela.r_addend = src[0].r_addend;
++  BFD_ASSERT(src[1].r_addend == 0);
++  BFD_ASSERT(src[2].r_addend == 0);
++
++  mirela.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info);
++  mirela.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info);
++  mirela.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info);
++
++  mips_elf64_swap_reloca_out (abfd, &mirela,
++                            (Elf64_Mips_External_Rela *) dst);
++}
++\f
++/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
++   dangerous relocation.  */
++
++static bfd_boolean
++mips_elf64_assign_gp (bfd *output_bfd, bfd_vma *pgp)
++{
++  unsigned int count;
++  asymbol **sym;
++  unsigned int i;
++
++  /* If we've already figured out what GP will be, just return it.  */
++  *pgp = _bfd_get_gp_value (output_bfd);
++  if (*pgp)
++    return TRUE;
++
++  count = bfd_get_symcount (output_bfd);
++  sym = bfd_get_outsymbols (output_bfd);
++
++  /* The linker script will have created a symbol named `_gp' with the
++     appropriate value.  */
++  if (sym == NULL)
++    i = count;
++  else
++    {
++      for (i = 0; i < count; i++, sym++)
++      {
++        register const char *name;
++
++        name = bfd_asymbol_name (*sym);
++        if (*name == '_' && strcmp (name, "_gp") == 0)
++          {
++            *pgp = bfd_asymbol_value (*sym);
++            _bfd_set_gp_value (output_bfd, *pgp);
++            break;
++          }
++      }
++    }
++
++  if (i >= count)
++    {
++      /* Only get the error once.  */
++      *pgp = 4;
++      _bfd_set_gp_value (output_bfd, *pgp);
++      return FALSE;
++    }
++
++  return TRUE;
++}
++
++/* We have to figure out the gp value, so that we can adjust the
++   symbol value correctly.  We look up the symbol _gp in the output
++   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
++   target data.  We don't need to adjust the symbol value for an
++   external symbol if we are producing relocatable output.  */
++
++static bfd_reloc_status_type
++mips_elf64_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
++                   char **error_message, bfd_vma *pgp)
++{
++  if (bfd_is_und_section (symbol->section)
++      && ! relocatable)
++    {
++      *pgp = 0;
++      return bfd_reloc_undefined;
++    }
++
++  *pgp = _bfd_get_gp_value (output_bfd);
++  if (*pgp == 0
++      && (! relocatable
++        || (symbol->flags & BSF_SECTION_SYM) != 0))
++    {
++      if (relocatable)
++      {
++        /* Make up a value.  */
++        *pgp = symbol->section->output_section->vma /*+ 0x4000*/;
++        _bfd_set_gp_value (output_bfd, *pgp);
++      }
++      else if (!mips_elf64_assign_gp (output_bfd, pgp))
++      {
++        *error_message =
++          (char *) _("GP relative relocation when _gp not defined");
++        return bfd_reloc_dangerous;
++      }
++    }
++
++  return bfd_reloc_ok;
++}
++
++/* Do a R_RISCV_GPREL16 relocation.  This is a 16 bit value which must
++   become the offset from the gp register.  */
++
++static bfd_reloc_status_type
++mips_elf64_gprel16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                        void *data, asection *input_section, bfd *output_bfd,
++                        char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++
++  /* If we're relocating, and this is an external symbol, we don't want
++     to change anything.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      reloc_entry->address += input_section->output_offset;
++      return bfd_reloc_ok;
++    }
++
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
++                           &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                      input_section, relocatable,
++                                      data, gp);
++}
++
++/* Do a R_RISCV_LITERAL relocation.  */
++
++static bfd_reloc_status_type
++mips_elf64_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                        void *data, asection *input_section, bfd *output_bfd,
++                        char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++
++  /* R_RISCV_LITERAL relocations are defined for local symbols only.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      *error_message = (char *)
++      _("literal relocation occurs for an external symbol");
++      return bfd_reloc_outofrange;
++    }
++
++  /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.  */
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
++                           &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                      input_section, relocatable,
++                                      data, gp);
++}
++
++/* Do a R_RISCV_GPREL32 relocation.  This is a 32 bit value which must
++   become the offset from the gp register.  */
++
++static bfd_reloc_status_type
++mips_elf64_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                        void *data, asection *input_section, bfd *output_bfd,
++                        char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_vma gp;
++  bfd_vma relocation;
++  bfd_vma val;
++
++  /* R_RISCV_GPREL32 relocations are defined for local symbols only.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      *error_message = (char *)
++      _("32bits gp relative relocation occurs for an external symbol");
++      return bfd_reloc_outofrange;
++    }
++
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable,
++                           error_message, &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  if (bfd_is_com_section (symbol->section))
++    relocation = 0;
++  else
++    relocation = symbol->value;
++
++  relocation += symbol->section->output_section->vma;
++  relocation += symbol->section->output_offset;
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  /* Set val to the offset into the section or symbol.  */
++  val = reloc_entry->addend;
++
++  if (reloc_entry->howto->partial_inplace)
++    val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
++
++  /* Adjust val for the final section location and GP value.  If we
++     are producing relocatable output, we don't want to do this for
++     an external symbol.  */
++  if (! relocatable
++      || (symbol->flags & BSF_SECTION_SYM) != 0)
++    val += relocation - gp;
++
++  if (reloc_entry->howto->partial_inplace)
++    bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
++  else
++    reloc_entry->addend = val;
++
++  if (relocatable)
++    reloc_entry->address += input_section->output_offset;
++
++  return bfd_reloc_ok;
++}
++
++/* Handle a mips16 GP relative reloc.  */
++
++static bfd_reloc_status_type
++mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                  void *data, asection *input_section, bfd *output_bfd,
++                  char **error_message)
++{
++  bfd_boolean relocatable;
++  bfd_reloc_status_type ret;
++  bfd_byte *location;
++  bfd_vma gp;
++
++  /* If we're relocating, and this is an external symbol, we don't want
++     to change anything.  */
++  if (output_bfd != NULL
++      && (symbol->flags & BSF_SECTION_SYM) == 0
++      && (symbol->flags & BSF_LOCAL) != 0)
++    {
++      reloc_entry->address += input_section->output_offset;
++      return bfd_reloc_ok;
++    }
++
++  if (output_bfd != NULL)
++    relocatable = TRUE;
++  else
++    {
++      relocatable = FALSE;
++      output_bfd = symbol->section->output_section->owner;
++    }
++
++  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
++                           &gp);
++  if (ret != bfd_reloc_ok)
++    return ret;
++
++  location = (bfd_byte *) data + reloc_entry->address;
++  ret = _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
++                                     input_section, relocatable,
++                                     data, gp);
++
++  return ret;
++}
++\f
++/* A mapping from BFD reloc types to MIPS ELF reloc types.  */
++
++struct elf_reloc_map {
++  bfd_reloc_code_real_type bfd_val;
++  enum elf_riscv_reloc_type elf_val;
++};
++
++static const struct elf_reloc_map mips_reloc_map[] =
++{
++  { BFD_RELOC_NONE, R_RISCV_NONE },
++  { BFD_RELOC_32, R_RISCV_32 },
++  /* There is no BFD reloc for R_RISCV_REL32.  */
++  { BFD_RELOC_64, R_RISCV_64 },
++  { BFD_RELOC_CTOR, R_RISCV_64 },
++  { BFD_RELOC_16_PCREL_S2, R_RISCV_PC16 },
++  { BFD_RELOC_HI16_S, R_RISCV_HI16 },
++  { BFD_RELOC_LO16, R_RISCV_LO16 },
++  { BFD_RELOC_GPREL16, R_RISCV_GPREL16 },
++  { BFD_RELOC_GPREL32, R_RISCV_GPREL32 },
++  { BFD_RELOC_MIPS_JMP, R_RISCV_26 },
++  { BFD_RELOC_MIPS_LITERAL, R_RISCV_LITERAL },
++  { BFD_RELOC_MIPS_GOT16, R_RISCV_GOT16 },
++  { BFD_RELOC_MIPS_CALL16, R_RISCV_CALL16 },
++  { BFD_RELOC_MIPS_GOT_DISP, R_RISCV_GOT_DISP },
++  { BFD_RELOC_MIPS_GOT_HI16, R_RISCV_GOT_HI16 },
++  { BFD_RELOC_MIPS_GOT_LO16, R_RISCV_GOT_LO16 },
++  { BFD_RELOC_MIPS_SUB, R_RISCV_SUB },
++  { BFD_RELOC_MIPS_INSERT_A, R_RISCV_INSERT_A },
++  { BFD_RELOC_MIPS_INSERT_B, R_RISCV_INSERT_B },
++  { BFD_RELOC_MIPS_DELETE, R_RISCV_DELETE },
++  { BFD_RELOC_MIPS_CALL_HI16, R_RISCV_CALL_HI16 },
++  { BFD_RELOC_MIPS_CALL_LO16, R_RISCV_CALL_LO16 },
++  { BFD_RELOC_MIPS_SCN_DISP, R_RISCV_SCN_DISP },
++  { BFD_RELOC_MIPS_REL16, R_RISCV_REL16 },
++  /* Use of R_RISCV_ADD_IMMEDIATE and R_RISCV_PJUMP is deprecated.  */
++  { BFD_RELOC_MIPS_RELGOT, R_RISCV_RELGOT },
++  { BFD_RELOC_MIPS_JALR, R_RISCV_JALR },
++  { BFD_RELOC_MIPS_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
++  { BFD_RELOC_MIPS_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
++  { BFD_RELOC_MIPS_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
++  { BFD_RELOC_MIPS_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
++  { BFD_RELOC_MIPS_TLS_GD, R_RISCV_TLS_GD },
++  { BFD_RELOC_MIPS_TLS_LDM, R_RISCV_TLS_LDM },
++  { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_RISCV_TLS_DTPREL_HI16 },
++  { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_RISCV_TLS_DTPREL_LO16 },
++  { BFD_RELOC_MIPS_TLS_GOTTPREL, R_RISCV_TLS_GOTTPREL },
++  { BFD_RELOC_MIPS_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
++  { BFD_RELOC_MIPS_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
++  { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_RISCV_TLS_TPREL_HI16 },
++  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_RISCV_TLS_TPREL_LO16 },
++  { BFD_RELOC_RISCV_TLS_GOT_HI16, R_RISCV_TLS_GOT_HI16 },
++  { BFD_RELOC_RISCV_TLS_GOT_LO16, R_RISCV_TLS_GOT_LO16 },
++  { BFD_RELOC_RISCV_TLS_GD_HI16, R_RISCV_TLS_GD_HI16 },
++  { BFD_RELOC_RISCV_TLS_GD_LO16, R_RISCV_TLS_GD_LO16 },
++  { BFD_RELOC_RISCV_TLS_LDM_HI16, R_RISCV_TLS_LDM_HI16 },
++  { BFD_RELOC_RISCV_TLS_LDM_LO16, R_RISCV_TLS_LDM_LO16 }
++};
++
++static const struct elf_reloc_map mips16_reloc_map[] =
++{
++  { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
++  { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
++};
++
++/* Given a BFD reloc type, return a howto structure.  */
++
++static reloc_howto_type *
++bfd_elf64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++                               bfd_reloc_code_real_type code)
++{
++  unsigned int i;
++  /* FIXME: We default to RELA here instead of choosing the right
++     relocation variant.  */
++  reloc_howto_type *howto_table = mips_elf64_howto_table_rela;
++  reloc_howto_type *howto16_table = mips16_elf64_howto_table_rela;
++
++  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
++       i++)
++    {
++      if (mips_reloc_map[i].bfd_val == code)
++      return &howto_table[(int) mips_reloc_map[i].elf_val];
++    }
++
++  for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
++       i++)
++    {
++      if (mips16_reloc_map[i].bfd_val == code)
++      return &howto16_table[(int) mips16_reloc_map[i].elf_val];
++    }
++
++  switch (code)
++    {
++    case BFD_RELOC_VTABLE_INHERIT:
++      return &elf_mips_gnu_vtinherit_howto;
++    case BFD_RELOC_VTABLE_ENTRY:
++      return &elf_mips_gnu_vtentry_howto;
++    case BFD_RELOC_MIPS_COPY:
++      return &elf_mips_copy_howto;
++    case BFD_RELOC_MIPS_JUMP_SLOT:
++      return &elf_mips_jump_slot_howto;
++    default:
++      bfd_set_error (bfd_error_bad_value);
++      return NULL;
++    }
++}
++
++static reloc_howto_type *
++bfd_elf64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++                               const char *r_name)
++{
++  unsigned int i;
++
++  for (i = 0;
++       i < (sizeof (mips_elf64_howto_table_rela)
++          / sizeof (mips_elf64_howto_table_rela[0])); i++)
++    if (mips_elf64_howto_table_rela[i].name != NULL
++      && strcasecmp (mips_elf64_howto_table_rela[i].name, r_name) == 0)
++      return &mips_elf64_howto_table_rela[i];
++
++  for (i = 0;
++       i < (sizeof (mips16_elf64_howto_table_rela)
++          / sizeof (mips16_elf64_howto_table_rela[0]));
++       i++)
++    if (mips16_elf64_howto_table_rela[i].name != NULL
++      && strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
++      return &mips16_elf64_howto_table_rela[i];
++
++  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
++    return &elf_mips_gnu_vtinherit_howto;
++  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0)
++    return &elf_mips_gnu_vtentry_howto;
++  if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0)
++    return &elf_mips_gnu_rel16_s2;
++  if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0)
++    return &elf_mips_gnu_rela16_s2;
++  if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0)
++    return &elf_mips_copy_howto;
++  if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0)
++    return &elf_mips_jump_slot_howto;
++
++  return NULL;
++}
++
++/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */
++
++static reloc_howto_type *
++mips_elf64_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p)
++{
++  switch (r_type)
++    {
++    case R_RISCV_GNU_VTINHERIT:
++      return &elf_mips_gnu_vtinherit_howto;
++    case R_RISCV_GNU_VTENTRY:
++      return &elf_mips_gnu_vtentry_howto;
++    case R_RISCV_GNU_REL16_S2:
++      if (rela_p)
++      return &elf_mips_gnu_rela16_s2;
++      else
++      return &elf_mips_gnu_rel16_s2;
++    case R_RISCV_COPY:
++      return &elf_mips_copy_howto;
++    case R_RISCV_JUMP_SLOT:
++      return &elf_mips_jump_slot_howto;
++    default:
++      if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
++      {
++        if (rela_p)
++          return &mips16_elf64_howto_table_rela[r_type - R_MIPS16_min];
++        else
++          return &mips16_elf64_howto_table_rel[r_type - R_MIPS16_min];
++      }
++      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max);
++      if (rela_p)
++      return &mips_elf64_howto_table_rela[r_type];
++      else
++      return &mips_elf64_howto_table_rel[r_type];
++      break;
++    }
++}
++
++/* Prevent relocation handling by bfd for MIPS ELF64.  */
++
++static void
++mips_elf64_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
++                            arelent *cache_ptr ATTRIBUTE_UNUSED,
++                            Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
++{
++  BFD_ASSERT (0);
++}
++
++static void
++mips_elf64_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
++                             arelent *cache_ptr ATTRIBUTE_UNUSED,
++                             Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
++{
++  BFD_ASSERT (0);
++}
++
++/* Since each entry in an SHT_REL or SHT_RELA section can represent up
++   to three relocs, we must tell the user to allocate more space.  */
++
++static long
++mips_elf64_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
++{
++  return (sec->reloc_count * 3 + 1) * sizeof (arelent *);
++}
++
++static long
++mips_elf64_get_dynamic_reloc_upper_bound (bfd *abfd)
++{
++  return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3;
++}
++
++/* We must also copy more relocations than the corresponding functions
++   in elf.c would, so the two following functions are slightly
++   modified from elf.c, that multiply the external relocation count by
++   3 to obtain the internal relocation count.  */
++
++static long
++mips_elf64_canonicalize_reloc (bfd *abfd, sec_ptr section,
++                             arelent **relptr, asymbol **symbols)
++{
++  arelent *tblptr;
++  unsigned int i;
++  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++
++  if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE))
++    return -1;
++
++  tblptr = section->relocation;
++  for (i = 0; i < section->reloc_count * 3; i++)
++    *relptr++ = tblptr++;
++
++  *relptr = NULL;
++
++  return section->reloc_count * 3;
++}
++
++static long
++mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
++                                     asymbol **syms)
++{
++  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
++  asection *s;
++  long ret;
++
++  if (elf_dynsymtab (abfd) == 0)
++    {
++      bfd_set_error (bfd_error_invalid_operation);
++      return -1;
++    }
++
++  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
++  ret = 0;
++  for (s = abfd->sections; s != NULL; s = s->next)
++    {
++      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
++        && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
++            || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
++      {
++        arelent *p;
++        long count, i;
++
++        if (! (*slurp_relocs) (abfd, s, syms, TRUE))
++          return -1;
++        count = s->size / elf_section_data (s)->this_hdr.sh_entsize * 3;
++        p = s->relocation;
++        for (i = 0; i < count; i++)
++          *storage++ = p++;
++        ret += count;
++      }
++    }
++
++  *storage = NULL;
++
++  return ret;
++}
++
++/* Read the relocations from one reloc section.  This is mostly copied
++   from elfcode.h, except for the changes to expand one external
++   relocation to 3 internal ones.  We must unfortunately set
++   reloc_count to the number of external relocations, because a lot of
++   generic code seems to depend on this.  */
++
++static bfd_boolean
++mips_elf64_slurp_one_reloc_table (bfd *abfd, asection *asect,
++                                Elf_Internal_Shdr *rel_hdr,
++                                bfd_size_type reloc_count,
++                                arelent *relents, asymbol **symbols,
++                                bfd_boolean dynamic)
++{
++  void *allocated;
++  bfd_byte *native_relocs;
++  arelent *relent;
++  bfd_vma i;
++  int entsize;
++  bfd_boolean rela_p;
++
++  allocated = bfd_malloc (rel_hdr->sh_size);
++  if (allocated == NULL)
++    return FALSE;
++
++  if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
++      || (bfd_bread (allocated, rel_hdr->sh_size, abfd)
++        != rel_hdr->sh_size))
++    goto error_return;
++
++  native_relocs = allocated;
++
++  entsize = rel_hdr->sh_entsize;
++  BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel)
++            || entsize == sizeof (Elf64_Mips_External_Rela));
++
++  if (entsize == sizeof (Elf64_Mips_External_Rel))
++    rela_p = FALSE;
++  else
++    rela_p = TRUE;
++
++  for (i = 0, relent = relents;
++       i < reloc_count;
++       i++, native_relocs += entsize)
++    {
++      Elf64_Mips_Internal_Rela rela;
++      bfd_boolean used_sym, used_ssym;
++      int ir;
++
++      if (entsize == sizeof (Elf64_Mips_External_Rela))
++      mips_elf64_swap_reloca_in (abfd,
++                                 (Elf64_Mips_External_Rela *) native_relocs,
++                                 &rela);
++      else
++      mips_elf64_swap_reloc_in (abfd,
++                                (Elf64_Mips_External_Rel *) native_relocs,
++                                &rela);
++
++      /* Each entry represents exactly three actual relocations.  */
++
++      used_sym = FALSE;
++      used_ssym = FALSE;
++      for (ir = 0; ir < 3; ir++)
++      {
++        enum elf_riscv_reloc_type type;
++
++        switch (ir)
++          {
++          default:
++            abort ();
++          case 0:
++            type = (enum elf_riscv_reloc_type) rela.r_type;
++            break;
++          case 1:
++            type = (enum elf_riscv_reloc_type) rela.r_type2;
++            break;
++          case 2:
++            type = (enum elf_riscv_reloc_type) rela.r_type3;
++            break;
++          }
++
++        /* Some types require symbols, whereas some do not.  */
++        switch (type)
++          {
++          case R_RISCV_NONE:
++          case R_RISCV_LITERAL:
++          case R_RISCV_INSERT_A:
++          case R_RISCV_INSERT_B:
++          case R_RISCV_DELETE:
++            relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
++            break;
++
++          default:
++            if (! used_sym)
++              {
++                if (rela.r_sym == STN_UNDEF)
++                  relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
++                else
++                  {
++                    asymbol **ps, *s;
++
++                    ps = symbols + rela.r_sym - 1;
++                    s = *ps;
++                    if ((s->flags & BSF_SECTION_SYM) == 0)
++                      relent->sym_ptr_ptr = ps;
++                    else
++                      relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
++                  }
++
++                used_sym = TRUE;
++              }
++            else if (! used_ssym)
++              {
++                switch (rela.r_ssym)
++                  {
++                  case RSS_UNDEF:
++                    relent->sym_ptr_ptr =
++                      bfd_abs_section_ptr->symbol_ptr_ptr;
++                    break;
++
++                  case RSS_GP:
++                  case RSS_GP0:
++                  case RSS_LOC:
++                    /* FIXME: I think these need to be handled using
++                       special howto structures.  */
++                    BFD_ASSERT (0);
++                    break;
++
++                  default:
++                    BFD_ASSERT (0);
++                    break;
++                  }
++
++                used_ssym = TRUE;
++              }
++            else
++              relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
++
++            break;
++          }
++
++        /* The address of an ELF reloc is section relative for an
++           object file, and absolute for an executable file or
++           shared library.  The address of a BFD reloc is always
++           section relative.  */
++        if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
++          relent->address = rela.r_offset;
++        else
++          relent->address = rela.r_offset - asect->vma;
++
++        relent->addend = rela.r_addend;
++
++        relent->howto = mips_elf64_rtype_to_howto (type, rela_p);
++
++        ++relent;
++      }
++    }
++
++  asect->reloc_count += (relent - relents) / 3;
++
++  if (allocated != NULL)
++    free (allocated);
++
++  return TRUE;
++
++ error_return:
++  if (allocated != NULL)
++    free (allocated);
++  return FALSE;
++}
++
++/* Read the relocations.  On Irix 6, there can be two reloc sections
++   associated with a single data section.  This is copied from
++   elfcode.h as well, with changes as small as accounting for 3
++   internal relocs per external reloc and resetting reloc_count to
++   zero before processing the relocs of a section.  */
++
++static bfd_boolean
++mips_elf64_slurp_reloc_table (bfd *abfd, asection *asect,
++                            asymbol **symbols, bfd_boolean dynamic)
++{
++  struct bfd_elf_section_data * const d = elf_section_data (asect);
++  Elf_Internal_Shdr *rel_hdr;
++  Elf_Internal_Shdr *rel_hdr2;
++  bfd_size_type reloc_count;
++  bfd_size_type reloc_count2;
++  arelent *relents;
++  bfd_size_type amt;
++
++  if (asect->relocation != NULL)
++    return TRUE;
++
++  if (! dynamic)
++    {
++      if ((asect->flags & SEC_RELOC) == 0
++        || asect->reloc_count == 0)
++      return TRUE;
++
++      rel_hdr = d->rel.hdr;
++      reloc_count = rel_hdr ? NUM_SHDR_ENTRIES (rel_hdr) : 0;
++      rel_hdr2 = d->rela.hdr;
++      reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0);
++
++      BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2);
++      BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset)
++                || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
++
++    }
++  else
++    {
++      /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
++       case because relocations against this section may use the
++       dynamic symbol table, and in that case bfd_section_from_shdr
++       in elf.c does not update the RELOC_COUNT.  */
++      if (asect->size == 0)
++      return TRUE;
++
++      rel_hdr = &d->this_hdr;
++      reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
++      rel_hdr2 = NULL;
++      reloc_count2 = 0;
++    }
++
++  /* Allocate space for 3 arelent structures for each Rel structure.  */
++  amt = (reloc_count + reloc_count2) * 3 * sizeof (arelent);
++  relents = bfd_alloc (abfd, amt);
++  if (relents == NULL)
++    return FALSE;
++
++  /* The slurp_one_reloc_table routine increments reloc_count.  */
++  asect->reloc_count = 0;
++
++  if (rel_hdr != NULL
++      && ! mips_elf64_slurp_one_reloc_table (abfd, asect,
++                                           rel_hdr, reloc_count,
++                                           relents,
++                                           symbols, dynamic))
++    return FALSE;
++  if (rel_hdr2 != NULL
++      && ! mips_elf64_slurp_one_reloc_table (abfd, asect,
++                                           rel_hdr2, reloc_count2,
++                                           relents + reloc_count * 3,
++                                           symbols, dynamic))
++    return FALSE;
++
++  asect->relocation = relents;
++  return TRUE;
++}
++
++/* Write out the relocations.  */
++
++static void
++mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data)
++{
++  bfd_boolean *failedp = data;
++  int count;
++  Elf_Internal_Shdr *rel_hdr;
++  unsigned int idx;
++
++  /* If we have already failed, don't do anything.  */
++  if (*failedp)
++    return;
++
++  if ((sec->flags & SEC_RELOC) == 0)
++    return;
++
++  /* The linker backend writes the relocs out itself, and sets the
++     reloc_count field to zero to inhibit writing them here.  Also,
++     sometimes the SEC_RELOC flag gets set even when there aren't any
++     relocs.  */
++  if (sec->reloc_count == 0)
++    return;
++
++  /* We can combine up to three relocs that refer to the same address
++     if the latter relocs have no associated symbol.  */
++  count = 0;
++  for (idx = 0; idx < sec->reloc_count; idx++)
++    {
++      bfd_vma addr;
++      unsigned int i;
++
++      ++count;
++
++      addr = sec->orelocation[idx]->address;
++      for (i = 0; i < 2; i++)
++      {
++        arelent *r;
++
++        if (idx + 1 >= sec->reloc_count)
++          break;
++        r = sec->orelocation[idx + 1];
++        if (r->address != addr
++            || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
++            || (*r->sym_ptr_ptr)->value != 0)
++          break;
++
++        /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
++
++        ++idx;
++      }
++    }
++
++  rel_hdr = _bfd_elf_single_rel_hdr (sec);
++
++  /* Do the actual relocation.  */
++
++  if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rel))
++    mips_elf64_write_rel (abfd, sec, rel_hdr, &count, data);
++  else if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rela))
++    mips_elf64_write_rela (abfd, sec, rel_hdr, &count, data);
++  else
++    BFD_ASSERT (0);
++}
++
++static void
++mips_elf64_write_rel (bfd *abfd, asection *sec,
++                    Elf_Internal_Shdr *rel_hdr,
++                    int *count, void *data)
++{
++  bfd_boolean *failedp = data;
++  Elf64_Mips_External_Rel *ext_rel;
++  unsigned int idx;
++  asymbol *last_sym = 0;
++  int last_sym_idx = 0;
++
++  rel_hdr->sh_size = rel_hdr->sh_entsize * *count;
++  rel_hdr->contents = bfd_alloc (abfd, rel_hdr->sh_size);
++  if (rel_hdr->contents == NULL)
++    {
++      *failedp = TRUE;
++      return;
++    }
++
++  ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents;
++  for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++)
++    {
++      arelent *ptr;
++      Elf64_Mips_Internal_Rela int_rel;
++      asymbol *sym;
++      int n;
++      unsigned int i;
++
++      ptr = sec->orelocation[idx];
++
++      /* The address of an ELF reloc is section relative for an object
++       file, and absolute for an executable file or shared library.
++       The address of a BFD reloc is always section relative.  */
++      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
++      int_rel.r_offset = ptr->address;
++      else
++      int_rel.r_offset = ptr->address + sec->vma;
++
++      sym = *ptr->sym_ptr_ptr;
++      if (sym == last_sym)
++      n = last_sym_idx;
++      else if (bfd_is_abs_section (sym->section) && sym->value == 0)
++      n = STN_UNDEF;
++      else
++      {
++        last_sym = sym;
++        n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
++        if (n < 0)
++          {
++            *failedp = TRUE;
++            return;
++          }
++        last_sym_idx = n;
++      }
++
++      int_rel.r_sym = n;
++      int_rel.r_ssym = RSS_UNDEF;
++
++      if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
++        && ! _bfd_elf_validate_reloc (abfd, ptr))
++      {
++        *failedp = TRUE;
++        return;
++      }
++
++      int_rel.r_type = ptr->howto->type;
++      int_rel.r_type2 = (int) R_RISCV_NONE;
++      int_rel.r_type3 = (int) R_RISCV_NONE;
++
++      for (i = 0; i < 2; i++)
++      {
++        arelent *r;
++
++        if (idx + 1 >= sec->reloc_count)
++          break;
++        r = sec->orelocation[idx + 1];
++        if (r->address != ptr->address
++            || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
++            || (*r->sym_ptr_ptr)->value != 0)
++          break;
++
++        /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
++
++        if (i == 0)
++          int_rel.r_type2 = r->howto->type;
++        else
++          int_rel.r_type3 = r->howto->type;
++
++        ++idx;
++      }
++
++      mips_elf64_swap_reloc_out (abfd, &int_rel, ext_rel);
++    }
++
++  BFD_ASSERT (ext_rel - (Elf64_Mips_External_Rel *) rel_hdr->contents
++            == *count);
++}
++
++static void
++mips_elf64_write_rela (bfd *abfd, asection *sec,
++                     Elf_Internal_Shdr *rela_hdr,
++                     int *count, void *data)
++{
++  bfd_boolean *failedp = data;
++  Elf64_Mips_External_Rela *ext_rela;
++  unsigned int idx;
++  asymbol *last_sym = 0;
++  int last_sym_idx = 0;
++
++  rela_hdr->sh_size = rela_hdr->sh_entsize * *count;
++  rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size);
++  if (rela_hdr->contents == NULL)
++    {
++      *failedp = TRUE;
++      return;
++    }
++
++  ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents;
++  for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++)
++    {
++      arelent *ptr;
++      Elf64_Mips_Internal_Rela int_rela;
++      asymbol *sym;
++      int n;
++      unsigned int i;
++
++      ptr = sec->orelocation[idx];
++
++      /* The address of an ELF reloc is section relative for an object
++       file, and absolute for an executable file or shared library.
++       The address of a BFD reloc is always section relative.  */
++      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
++      int_rela.r_offset = ptr->address;
++      else
++      int_rela.r_offset = ptr->address + sec->vma;
++
++      sym = *ptr->sym_ptr_ptr;
++      if (sym == last_sym)
++      n = last_sym_idx;
++      else if (bfd_is_abs_section (sym->section) && sym->value == 0)
++      n = STN_UNDEF;
++      else
++      {
++        last_sym = sym;
++        n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
++        if (n < 0)
++          {
++            *failedp = TRUE;
++            return;
++          }
++        last_sym_idx = n;
++      }
++
++      int_rela.r_sym = n;
++      int_rela.r_addend = ptr->addend;
++      int_rela.r_ssym = RSS_UNDEF;
++
++      if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
++        && ! _bfd_elf_validate_reloc (abfd, ptr))
++      {
++        *failedp = TRUE;
++        return;
++      }
++
++      int_rela.r_type = ptr->howto->type;
++      int_rela.r_type2 = (int) R_RISCV_NONE;
++      int_rela.r_type3 = (int) R_RISCV_NONE;
++
++      for (i = 0; i < 2; i++)
++      {
++        arelent *r;
++
++        if (idx + 1 >= sec->reloc_count)
++          break;
++        r = sec->orelocation[idx + 1];
++        if (r->address != ptr->address
++            || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
++            || (*r->sym_ptr_ptr)->value != 0)
++          break;
++
++        /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */
++
++        if (i == 0)
++          int_rela.r_type2 = r->howto->type;
++        else
++          int_rela.r_type3 = r->howto->type;
++
++        ++idx;
++      }
++
++      mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela);
++    }
++
++  BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents
++            == *count);
++}
++\f
++/* Set the right machine number for a MIPS ELF file.  */
++
++static bfd_boolean
++mips_elf64_object_p (bfd *abfd)
++{
++  unsigned long mach;
++
++  mach = _bfd_elf_riscv_mach (elf_elfheader (abfd)->e_flags);
++  bfd_default_set_arch_mach (abfd, bfd_arch_riscv, mach);
++  return TRUE;
++}
++
++/* Support for core dump NOTE sections.  */
++static bfd_boolean
++elf64_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
++{
++  int offset;
++  unsigned int size;
++
++  switch (note->descsz)
++    {
++      default:
++      return FALSE;
++
++      case 480:               /* Linux/MIPS - N64 kernel */
++      /* pr_cursig */
++      elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
++
++      /* pr_pid */
++      elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
++
++      /* pr_reg */
++      offset = 112;
++      size = 360;
++
++      break;
++    }
++
++  /* Make a ".reg/999" section.  */
++  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
++                                        size, note->descpos + offset);
++}
++
++static bfd_boolean
++elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
++{
++  switch (note->descsz)
++    {
++      default:
++      return FALSE;
++
++      case 136:               /* Linux/MIPS - N64 kernel elf_prpsinfo */
++      elf_tdata (abfd)->core_program
++       = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
++      elf_tdata (abfd)->core_command
++       = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
++    }
++
++  /* Note that for some reason, a spurious space is tacked
++     onto the end of the args in some (at least one anyway)
++     implementations, so strip it off if it exists.  */
++
++  {
++    char *command = elf_tdata (abfd)->core_command;
++    int n = strlen (command);
++
++    if (0 < n && command[n - 1] == ' ')
++      command[n - 1] = '\0';
++  }
++
++  return TRUE;
++}
++\f
++/* ECOFF swapping routines.  These are used when dealing with the
++   .mdebug section, which is in the ECOFF debugging format.  */
++static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap =
++{
++  /* Symbol table magic number.  */
++  magicSym2,
++  /* Alignment of debugging information.  E.g., 4.  */
++  8,
++  /* Sizes of external symbolic information.  */
++  sizeof (struct hdr_ext),
++  sizeof (struct dnr_ext),
++  sizeof (struct pdr_ext),
++  sizeof (struct sym_ext),
++  sizeof (struct opt_ext),
++  sizeof (struct fdr_ext),
++  sizeof (struct rfd_ext),
++  sizeof (struct ext_ext),
++  /* Functions to swap in external symbolic data.  */
++  ecoff_swap_hdr_in,
++  ecoff_swap_dnr_in,
++  ecoff_swap_pdr_in,
++  ecoff_swap_sym_in,
++  ecoff_swap_opt_in,
++  ecoff_swap_fdr_in,
++  ecoff_swap_rfd_in,
++  ecoff_swap_ext_in,
++  _bfd_ecoff_swap_tir_in,
++  _bfd_ecoff_swap_rndx_in,
++  /* Functions to swap out external symbolic data.  */
++  ecoff_swap_hdr_out,
++  ecoff_swap_dnr_out,
++  ecoff_swap_pdr_out,
++  ecoff_swap_sym_out,
++  ecoff_swap_opt_out,
++  ecoff_swap_fdr_out,
++  ecoff_swap_rfd_out,
++  ecoff_swap_ext_out,
++  _bfd_ecoff_swap_tir_out,
++  _bfd_ecoff_swap_rndx_out,
++  /* Function to read in symbolic data.  */
++  _bfd_riscv_elf_read_ecoff_info
++};
++\f
++/* Relocations in the 64 bit MIPS ELF ABI are more complex than in
++   standard ELF.  This structure is used to redirect the relocation
++   handling routines.  */
++
++const struct elf_size_info mips_elf64_size_info =
++{
++  sizeof (Elf64_External_Ehdr),
++  sizeof (Elf64_External_Phdr),
++  sizeof (Elf64_External_Shdr),
++  sizeof (Elf64_Mips_External_Rel),
++  sizeof (Elf64_Mips_External_Rela),
++  sizeof (Elf64_External_Sym),
++  sizeof (Elf64_External_Dyn),
++  sizeof (Elf_External_Note),
++  4,          /* hash-table entry size */
++  3,          /* internal relocations per external relocations */
++  64,         /* arch_size */
++  3,          /* log_file_align */
++  ELFCLASS64,
++  EV_CURRENT,
++  bfd_elf64_write_out_phdrs,
++  bfd_elf64_write_shdrs_and_ehdr,
++  bfd_elf64_checksum_contents,
++  mips_elf64_write_relocs,
++  bfd_elf64_swap_symbol_in,
++  bfd_elf64_swap_symbol_out,
++  mips_elf64_slurp_reloc_table,
++  bfd_elf64_slurp_symbol_table,
++  bfd_elf64_swap_dyn_in,
++  bfd_elf64_swap_dyn_out,
++  mips_elf64_be_swap_reloc_in,
++  mips_elf64_be_swap_reloc_out,
++  mips_elf64_be_swap_reloca_in,
++  mips_elf64_be_swap_reloca_out
++};
++
++#define ELF_ARCH                      bfd_arch_riscv
++#define ELF_TARGET_ID                 MIPS_ELF_DATA
++#define ELF_MACHINE_CODE              EM_RISCV
++
++#define elf_backend_collect           TRUE
++#define elf_backend_type_change_ok    TRUE
++#define elf_backend_can_gc_sections   TRUE
++#define elf_info_to_howto             mips_elf64_info_to_howto_rela
++#define elf_info_to_howto_rel         mips_elf64_info_to_howto_rel
++#define elf_backend_object_p          mips_elf64_object_p
++#define elf_backend_symbol_processing _bfd_riscv_elf_symbol_processing
++#define elf_backend_section_processing        _bfd_riscv_elf_section_processing
++#define elf_backend_section_from_shdr _bfd_riscv_elf_section_from_shdr
++#define elf_backend_fake_sections     _bfd_riscv_elf_fake_sections
++#define elf_backend_section_from_bfd_section \
++                              _bfd_riscv_elf_section_from_bfd_section
++#define elf_backend_add_symbol_hook   _bfd_riscv_elf_add_symbol_hook
++#define elf_backend_link_output_symbol_hook \
++                              _bfd_riscv_elf_link_output_symbol_hook
++#define elf_backend_create_dynamic_sections \
++                              _bfd_riscv_elf_create_dynamic_sections
++#define elf_backend_check_relocs      _bfd_riscv_elf_check_relocs
++#define elf_backend_merge_symbol_attribute \
++                              _bfd_riscv_elf_merge_symbol_attribute
++#define elf_backend_get_target_dtag   _bfd_riscv_elf_get_target_dtag
++#define elf_backend_adjust_dynamic_symbol \
++                              _bfd_riscv_elf_adjust_dynamic_symbol
++#define elf_backend_always_size_sections \
++                              _bfd_riscv_elf_always_size_sections
++#define elf_backend_size_dynamic_sections \
++                              _bfd_riscv_elf_size_dynamic_sections
++#define elf_backend_init_index_section        _bfd_elf_init_1_index_section
++#define elf_backend_relocate_section    _bfd_riscv_elf_relocate_section
++#define elf_backend_finish_dynamic_symbol \
++                              _bfd_riscv_elf_finish_dynamic_symbol
++#define elf_backend_finish_dynamic_sections \
++                              _bfd_riscv_elf_finish_dynamic_sections
++#define elf_backend_final_write_processing \
++                              _bfd_riscv_elf_final_write_processing
++#define elf_backend_additional_program_headers \
++                              _bfd_riscv_elf_additional_program_headers
++#define elf_backend_modify_segment_map        _bfd_riscv_elf_modify_segment_map
++#define elf_backend_gc_mark_hook      _bfd_riscv_elf_gc_mark_hook
++#define elf_backend_gc_sweep_hook     _bfd_riscv_elf_gc_sweep_hook
++#define elf_backend_copy_indirect_symbol \
++                                      _bfd_riscv_elf_copy_indirect_symbol
++#define elf_backend_ignore_discarded_relocs \
++                                      _bfd_riscv_elf_ignore_discarded_relocs
++#define elf_backend_mips_rtype_to_howto       mips_elf64_rtype_to_howto
++#define elf_backend_ecoff_debug_swap  &mips_elf64_ecoff_debug_swap
++#define elf_backend_size_info         mips_elf64_size_info
++
++#define elf_backend_grok_prstatus     elf64_mips_grok_prstatus
++#define elf_backend_grok_psinfo               elf64_mips_grok_psinfo
++
++#define elf_backend_got_header_size   (4 * MIPS_RESERVED_GOTNO)
++
++/* MIPS ELF64 can use a mixture of REL and RELA, but some Relocations
++   work better/work only in RELA, so we default to this.  */
++#define elf_backend_may_use_rel_p     1
++#define elf_backend_may_use_rela_p    1
++#define elf_backend_default_use_rela_p        1
++#define elf_backend_rela_plts_and_copies_p 0
++#define elf_backend_plt_readonly      1
++#define elf_backend_plt_sym_val               _bfd_riscv_elf_plt_sym_val
++
++#define elf_backend_sign_extend_vma   TRUE
++
++#define elf_backend_write_section     _bfd_riscv_elf_write_section
++
++/* We don't set bfd_elf64_bfd_is_local_label_name because the 32-bit
++   MIPS-specific function only applies to IRIX5, which had no 64-bit
++   ABI.  */
++#define bfd_elf64_find_nearest_line   _bfd_riscv_elf_find_nearest_line
++#define bfd_elf64_find_inliner_info   _bfd_riscv_elf_find_inliner_info
++#define bfd_elf64_new_section_hook    _bfd_riscv_elf_new_section_hook
++#define bfd_elf64_set_section_contents        _bfd_riscv_elf_set_section_contents
++#define bfd_elf64_bfd_get_relocated_section_contents \
++                              _bfd_elf_riscv_get_relocated_section_contents
++#define bfd_elf64_bfd_link_hash_table_create \
++                              _bfd_riscv_elf_link_hash_table_create
++#define bfd_elf64_bfd_final_link      _bfd_riscv_elf_final_link
++#define bfd_elf64_bfd_merge_private_bfd_data \
++                              _bfd_riscv_elf_merge_private_bfd_data
++#define bfd_elf64_bfd_set_private_flags       _bfd_riscv_elf_set_private_flags
++#define bfd_elf64_bfd_print_private_bfd_data \
++                              _bfd_riscv_elf_print_private_bfd_data
++
++#define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
++#define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
++#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
++#define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
++#define bfd_elf64_bfd_relax_section     _bfd_riscv_relax_section
++
++/* MIPS ELF64 archive functions.  */
++#define bfd_elf64_archive_functions
++extern bfd_boolean bfd_elf64_archive_slurp_armap
++  (bfd *);
++extern bfd_boolean bfd_elf64_archive_write_armap
++  (bfd *, unsigned int, struct orl *, unsigned int, int);
++#define bfd_elf64_archive_slurp_extended_name_table \
++                      _bfd_archive_coff_slurp_extended_name_table
++#define bfd_elf64_archive_construct_extended_name_table \
++                      _bfd_archive_coff_construct_extended_name_table
++#define bfd_elf64_archive_truncate_arname \
++                      _bfd_archive_coff_truncate_arname
++#define bfd_elf64_archive_read_ar_hdr _bfd_archive_coff_read_ar_hdr
++#define bfd_elf64_archive_write_ar_hdr        _bfd_archive_coff_write_ar_hdr
++#define bfd_elf64_archive_openr_next_archived_file \
++                      _bfd_archive_coff_openr_next_archived_file
++#define bfd_elf64_archive_get_elt_at_index \
++                      _bfd_archive_coff_get_elt_at_index
++#define bfd_elf64_archive_generic_stat_arch_elt \
++                      _bfd_archive_coff_generic_stat_arch_elt
++#define bfd_elf64_archive_update_armap_timestamp \
++                      _bfd_archive_coff_update_armap_timestamp
++
++/* The SGI style (n)64 NewABI.  */
++#define TARGET_LITTLE_SYM             bfd_elf64_littleriscv_vec
++#define TARGET_LITTLE_NAME            "elf64-littleriscv"
++#define TARGET_BIG_SYM                        bfd_elf64_bigriscv_vec
++#define TARGET_BIG_NAME                       "elf64-bigriscv"
++
++#define ELF_MAXPAGESIZE                       0x10000
++#define ELF_COMMONPAGESIZE            0x1000
++
++#include "elf64-target.h"
+diff -ruN binutils-2.21.1-orig/bfd/elfxx-riscv.c binutils-2.21.1/bfd/elfxx-riscv.c
+--- binutils-2.21.1-orig/bfd/elfxx-riscv.c     1969-12-31 16:00:00.000000000 -0800
++++ binutils-2.21.1/bfd/elfxx-riscv.c  2011-10-22 18:50:03.000000000 -0700
+@@ -0,0 +1,9383 @@
++/* vim: set ts=8 */
++/* MIPS-specific support for ELF
++   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
++   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
++
++   Most of the information added by Ian Lance Taylor, Cygnus Support,
++   <ian@cygnus.com>.
++   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
++   <mark@codesourcery.com>
++   Traditional MIPS targets support added by Koundinya.K, Dansk Data
++   Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
++
++   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; if not, write to the Free Software
++   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
++   MA 02110-1301, USA.  */
++
++
++/* This file handles functionality common to the different MIPS ABI's.  */
++
++#include "sysdep.h"
++#include "bfd.h"
++#include "libbfd.h"
++#include "libiberty.h"
++#include "elf-bfd.h"
++#include "elfxx-riscv.h"
++#include "elf/riscv.h"
++#include "opcode/riscv.h"
++
++/* Get the ECOFF swapping routines.  */
++#include "coff/sym.h"
++#include "coff/symconst.h"
++#include "coff/ecoff.h"
++#include "coff/mips.h"
++
++#include "hashtab.h"
++
++/* This structure is used to hold information about one GOT entry.
++   There are three types of entry:
++
++      (1) absolute addresses
++          (abfd == NULL)
++      (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
++          (abfd != NULL, symndx >= 0)
++      (3) SYMBOL addresses, where SYMBOL is not local to an input bfd
++          (abfd != NULL, symndx == -1)
++
++   Type (3) entries are treated differently for different types of GOT.
++   In the "master" GOT -- i.e.  the one that describes every GOT
++   reference needed in the link -- the mips_got_entry is keyed on both
++   the symbol and the input bfd that references it.  If it turns out
++   that we need multiple GOTs, we can then use this information to
++   create separate GOTs for each input bfd.
++
++   However, we want each of these separate GOTs to have at most one
++   entry for a given symbol, so their type (3) entries are keyed only
++   on the symbol.  The input bfd given by the "abfd" field is somewhat
++   arbitrary in this case.
++
++   This means that when there are multiple GOTs, each GOT has a unique
++   mips_got_entry for every symbol within it.  We can therefore use the
++   mips_got_entry fields (tls_type and gotidx) to track the symbol's
++   GOT index.
++
++   However, if it turns out that we need only a single GOT, we continue
++   to use the master GOT to describe it.  There may therefore be several
++   mips_got_entries for the same symbol, each with a different input bfd.
++   We want to make sure that each symbol gets a unique GOT entry, so when
++   there's a single GOT, we use the symbol's hash entry, not the
++   mips_got_entry fields, to track a symbol's GOT index.  */
++struct mips_got_entry
++{
++  /* The input bfd in which the symbol is defined.  */
++  bfd *abfd;
++  /* The index of the symbol, as stored in the relocation r_info, if
++     we have a local symbol; -1 otherwise.  */
++  long symndx;
++  union
++  {
++    /* If abfd == NULL, an address that must be stored in the got.  */
++    bfd_vma address;
++    /* If abfd != NULL && symndx != -1, the addend of the relocation
++       that should be added to the symbol value.  */
++    bfd_vma addend;
++    /* If abfd != NULL && symndx == -1, the hash table entry
++       corresponding to symbol in the GOT.  The symbol's entry
++       is in the local area if h->global_got_area is GGA_NONE,
++       otherwise it is in the global area.  */
++    struct mips_elf_link_hash_entry *h;
++  } d;
++
++  /* The TLS types included in this GOT entry (specifically, GD and
++     IE).  The GD and IE flags can be added as we encounter new
++     relocations.  LDM can also be set; it will always be alone, not
++     combined with any GD or IE flags.  An LDM GOT entry will be
++     a local symbol entry with r_symndx == 0.  */
++  unsigned char tls_type;
++
++  /* The offset from the beginning of the .got section to the entry
++     corresponding to this symbol+addend.  If it's a global symbol
++     whose offset is yet to be decided, it's going to be -1.  */
++  long gotidx;
++};
++
++/* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND].
++   The structures form a non-overlapping list that is sorted by increasing
++   MIN_ADDEND.  */
++struct mips_got_page_range
++{
++  struct mips_got_page_range *next;
++  bfd_signed_vma min_addend;
++  bfd_signed_vma max_addend;
++};
++
++/* This structure describes the range of addends that are applied to page
++   relocations against a given symbol.  */
++struct mips_got_page_entry
++{
++  /* The input bfd in which the symbol is defined.  */
++  bfd *abfd;
++  /* The index of the symbol, as stored in the relocation r_info.  */
++  long symndx;
++  /* The ranges for this page entry.  */
++  struct mips_got_page_range *ranges;
++  /* The maximum number of page entries needed for RANGES.  */
++  bfd_vma num_pages;
++};
++
++/* This structure is used to hold .got information when linking.  */
++
++struct mips_got_info
++{
++  /* The global symbol in the GOT with the lowest index in the dynamic
++     symbol table.  */
++  struct elf_link_hash_entry *global_gotsym;
++  /* The number of global .got entries.  */
++  unsigned int global_gotno;
++  /* The number of global .got entries that are in the GGA_RELOC_ONLY area.  */
++  unsigned int reloc_only_gotno;
++  /* The number of .got slots used for TLS.  */
++  unsigned int tls_gotno;
++  /* The first unused TLS .got entry.  Used only during
++     mips_elf_initialize_tls_index.  */
++  unsigned int tls_assigned_gotno;
++  /* The number of local .got entries, eventually including page entries.  */
++  unsigned int local_gotno;
++  /* The maximum number of page entries needed.  */
++  unsigned int page_gotno;
++  /* The number of local .got entries we have used.  */
++  unsigned int assigned_gotno;
++  /* A hash table holding members of the got.  */
++  struct htab *got_entries;
++  /* A hash table of mips_got_page_entry structures.  */
++  struct htab *got_page_entries;
++  /* A hash table mapping input bfds to other mips_got_info.  NULL
++     unless multi-got was necessary.  */
++  struct htab *bfd2got;
++  /* In multi-got links, a pointer to the next got (err, rather, most
++     of the time, it points to the previous got).  */
++  struct mips_got_info *next;
++  /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
++     for none, or MINUS_TWO for not yet assigned.  This is needed
++     because a single-GOT link may have multiple hash table entries
++     for the LDM.  It does not get initialized in multi-GOT mode.  */
++  bfd_vma tls_ldm_offset;
++};
++
++/* Map an input bfd to a got in a multi-got link.  */
++
++struct mips_elf_bfd2got_hash
++{
++  bfd *bfd;
++  struct mips_got_info *g;
++};
++
++/* Structure passed when traversing the bfd2got hash table, used to
++   create and merge bfd's gots.  */
++
++struct mips_elf_got_per_bfd_arg
++{
++  /* A hashtable that maps bfds to gots.  */
++  htab_t bfd2got;
++  /* The output bfd.  */
++  bfd *obfd;
++  /* The link information.  */
++  struct bfd_link_info *info;
++  /* A pointer to the primary got, i.e., the one that's going to get
++     the implicit relocations from DT_MIPS_LOCAL_GOTNO and
++     DT_MIPS_GOTSYM.  */
++  struct mips_got_info *primary;
++  /* A non-primary got we're trying to merge with other input bfd's
++     gots.  */
++  struct mips_got_info *current;
++  /* The maximum number of got entries that can be addressed with a
++     16-bit offset.  */
++  unsigned int max_count;
++  /* The maximum number of page entries needed by each got.  */
++  unsigned int max_pages;
++  /* The total number of global entries which will live in the
++     primary got and be automatically relocated.  This includes
++     those not referenced by the primary GOT but included in
++     the "master" GOT.  */
++  unsigned int global_count;
++};
++
++/* Another structure used to pass arguments for got entries traversal.  */
++
++struct mips_elf_set_global_got_offset_arg
++{
++  struct mips_got_info *g;
++  int value;
++  unsigned int needed_relocs;
++  struct bfd_link_info *info;
++};
++
++/* A structure used to count TLS relocations or GOT entries, for GOT
++   entry or ELF symbol table traversal.  */
++
++struct mips_elf_count_tls_arg
++{
++  struct bfd_link_info *info;
++  unsigned int needed;
++};
++
++struct _mips_elf_section_data
++{
++  struct bfd_elf_section_data elf;
++  union
++  {
++    bfd_byte *tdata;
++  } u;
++};
++
++#define mips_elf_section_data(sec) \
++  ((struct _mips_elf_section_data *) elf_section_data (sec))
++
++#define is_mips_elf(bfd)                              \
++  (bfd_get_flavour (bfd) == bfd_target_elf_flavour    \
++   && elf_tdata (bfd) != NULL                         \
++   && elf_object_id (bfd) == MIPS_ELF_DATA)
++
++/* The ABI says that every symbol used by dynamic relocations must have
++   a global GOT entry.  Among other things, this provides the dynamic
++   linker with a free, directly-indexed cache.  The GOT can therefore
++   contain symbols that are not referenced by GOT relocations themselves
++   (in other words, it may have symbols that are not referenced by things
++   like R_RISCV_GOT16).
++
++   GOT relocations are less likely to overflow if we put the associated
++   GOT entries towards the beginning.  We therefore divide the global
++   GOT entries into two areas: "normal" and "reloc-only".  Entries in
++   the first area can be used for both dynamic relocations and GP-relative
++   accesses, while those in the "reloc-only" area are for dynamic
++   relocations only.
++
++   These GGA_* ("Global GOT Area") values are organised so that lower
++   values are more general than higher values.  Also, non-GGA_NONE
++   values are ordered by the position of the area in the GOT.  */
++#define GGA_NORMAL 0
++#define GGA_RELOC_ONLY 1
++#define GGA_NONE 2
++
++/* Information about a non-PIC interface to a PIC function.  There are
++   two ways of creating these interfaces.  The first is to add:
++
++      lui     t7,%hi(func)
++      addi    t7,t7,%lo(func)
++
++   immediately before a PIC function "func".  The second is to add:
++
++      lui     t7,%hi(func)
++      addi    t7,t7,%lo(func)
++      j       func
++
++   to a separate trampoline section.
++
++   Stubs of the first kind go in a new section immediately before the
++   target function.  Stubs of the second kind go in a single section
++   pointed to by the hash table's "strampoline" field.  */
++struct mips_elf_la25_stub {
++  /* The generated section that contains this stub.  */
++  asection *stub_section;
++
++  /* The offset of the stub from the start of STUB_SECTION.  */
++  bfd_vma offset;
++
++  /* One symbol for the original function.  Its location is available
++     in H->root.root.u.def.  */
++  struct mips_elf_link_hash_entry *h;
++};
++
++/* This structure is passed to mips_elf_sort_hash_table_f when sorting
++   the dynamic symbols.  */
++
++struct mips_elf_hash_sort_data
++{
++  /* The symbol in the global GOT with the lowest dynamic symbol table
++     index.  */
++  struct elf_link_hash_entry *low;
++  /* The least dynamic symbol table index corresponding to a non-TLS
++     symbol with a GOT entry.  */
++  long min_got_dynindx;
++  /* The greatest dynamic symbol table index corresponding to a symbol
++     with a GOT entry that is not referenced (e.g., a dynamic symbol
++     with dynamic relocations pointing to it from non-primary GOTs).  */
++  long max_unref_got_dynindx;
++  /* The greatest dynamic symbol table index not corresponding to a
++     symbol without a GOT entry.  */
++  long max_non_got_dynindx;
++};
++
++/* The MIPS ELF linker needs additional information for each symbol in
++   the global hash table.  */
++
++struct mips_elf_link_hash_entry
++{
++  struct elf_link_hash_entry root;
++
++  /* External symbol information.  */
++  EXTR esym;
++
++  /* The la25 stub we have created for ths symbol, if any.  */
++  struct mips_elf_la25_stub *la25_stub;
++
++  /* Number of R_RISCV_32, R_RISCV_REL32, or R_RISCV_64 relocs against
++     this symbol.  */
++  unsigned int possibly_dynamic_relocs;
++
++#define GOT_NORMAL    0
++#define GOT_TLS_GD    1
++#define GOT_TLS_LDM   2
++#define GOT_TLS_IE    4
++#define GOT_TLS_OFFSET_DONE    0x40
++#define GOT_TLS_DONE    0x80
++  unsigned char tls_type;
++
++  /* This is only used in single-GOT mode; in multi-GOT mode there
++     is one mips_got_entry per GOT entry, so the offset is stored
++     there.  In single-GOT mode there may be many mips_got_entry
++     structures all referring to the same GOT slot.  It might be
++     possible to use root.got.offset instead, but that field is
++     overloaded already.  */
++  bfd_vma tls_got_offset;
++
++  /* The highest GGA_* value that satisfies all references to this symbol.  */
++  unsigned int global_got_area : 2;
++
++  /* True if all GOT relocations against this symbol are for calls.  This is
++     a looser condition than no_fn_stub below, because there may be other
++     non-call non-GOT relocations against the symbol.  */
++  unsigned int got_only_for_calls : 1;
++
++  /* True if one of the relocations described by possibly_dynamic_relocs
++     is against a readonly section.  */
++  unsigned int readonly_reloc : 1;
++
++  /* True if there is a relocation against this symbol that must be
++     resolved by the static linker (in other words, if the relocation
++     cannot possibly be made dynamic).  */
++  unsigned int has_static_relocs : 1;
++
++  /* True if we must not create a .MIPS.stubs entry for this symbol.
++     This is set, for example, if there are relocations related to
++     taking the function's address, i.e. any but R_RISCV_CALL*16 ones.
++     See "MIPS ABI Supplement, 3rd Edition", p. 4-20.  */
++  unsigned int no_fn_stub : 1;
++
++  /* True if this symbol is referenced by branch relocations from
++     any non-PIC input file.  This is used to determine whether an
++     la25 stub is required.  */
++  unsigned int has_nonpic_branches : 1;
++
++  /* Does this symbol need a traditional MIPS lazy-binding stub
++     (as opposed to a PLT entry)?  */
++  unsigned int needs_lazy_stub : 1;
++};
++
++/* MIPS ELF linker hash table.  */
++
++struct mips_elf_link_hash_table
++{
++  struct elf_link_hash_table root;
++#if 0
++  /* We no longer use this.  */
++  /* String section indices for the dynamic section symbols.  */
++  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES];
++#endif
++
++  /* The number of .rtproc entries.  */
++  bfd_size_type procedure_count;
++
++  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
++     entry is set to the address of __rld_obj_head as in IRIX5.  */
++  bfd_boolean use_rld_obj_head;
++
++  /* This is the value of the __rld_map or __rld_obj_head symbol.  */
++  bfd_vma rld_value;
++
++  /* True if we can generate copy relocs and PLTs.  */
++  bfd_boolean use_plts_and_copy_relocs;
++
++  /* Shortcuts to some dynamic sections, or NULL if they are not
++     being used.  */
++  asection *srelbss;
++  asection *sdynbss;
++  asection *srelplt;
++  asection *srelplt2;
++  asection *sgotplt;
++  asection *splt;
++  asection *sstubs;
++  asection *sgot;
++
++  /* The master GOT information.  */
++  struct mips_got_info *got_info;
++
++  /* The size of the PLT header in bytes.  */
++  bfd_vma plt_header_size;
++
++  /* The size of a PLT entry in bytes.  */
++  bfd_vma plt_entry_size;
++
++  /* The number of functions that need a lazy-binding stub.  */
++  bfd_vma lazy_stub_count;
++
++  /* The size of a function stub entry in bytes.  */
++  bfd_vma function_stub_size;
++
++  /* The number of reserved entries at the beginning of the GOT.  */
++  unsigned int reserved_gotno;
++
++  /* The section used for mips_elf_la25_stub trampolines.
++     See the comment above that structure for details.  */
++  asection *strampoline;
++
++  /* A table of mips_elf_la25_stubs, indexed by (input_section, offset)
++     pairs.  */
++  htab_t la25_stubs;
++
++  /* A function FN (NAME, IS, OS) that creates a new input section
++     called NAME and links it to output section OS.  If IS is nonnull,
++     the new section should go immediately before it, otherwise it
++     should go at the (current) beginning of OS.
++
++     The function returns the new section on success, otherwise it
++     returns null.  */
++  asection *(*add_stub_section) (const char *, asection *, asection *);
++};
++
++/* Get the MIPS ELF linker hash table from a link_info structure.  */
++
++#define mips_elf_hash_table(p) \
++  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
++  == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL)
++
++/* A structure used to communicate with htab_traverse callbacks.  */
++struct mips_htab_traverse_info
++{
++  /* The usual link-wide information.  */
++  struct bfd_link_info *info;
++  bfd *output_bfd;
++
++  /* Starts off FALSE and is set to TRUE if the link should be aborted.  */
++  bfd_boolean error;
++};
++
++#define TLS_RELOC_P(r_type) \
++  (r_type == R_RISCV_TLS_DTPMOD32             \
++   || r_type == R_RISCV_TLS_DTPMOD64          \
++   || r_type == R_RISCV_TLS_DTPREL32          \
++   || r_type == R_RISCV_TLS_DTPREL64          \
++   || TLS_GD_RELOC_P(r_type)                  \
++   || TLS_LDM_RELOC_P(r_type)                 \
++   || r_type == R_RISCV_TLS_LDM                       \
++   || r_type == R_RISCV_TLS_DTPREL_HI16               \
++   || r_type == R_RISCV_TLS_DTPREL_LO16               \
++   || TLS_GOTTPREL_RELOC_P(r_type)            \
++   || r_type == R_RISCV_TLS_TPREL32           \
++   || r_type == R_RISCV_TLS_TPREL64           \
++   || r_type == R_RISCV_TLS_TPREL_HI16                \
++   || r_type == R_RISCV_TLS_TPREL_LO16)
++
++#define TLS_GOTTPREL_RELOC_P(r_type) \
++  ((r_type) == R_RISCV_TLS_GOTTPREL           \
++   || (r_type) == R_RISCV_TLS_GOT_HI16                \
++   || (r_type) == R_RISCV_TLS_GOT_LO16)
++
++#define TLS_GD_RELOC_P(r_type) \
++  ((r_type) == R_RISCV_TLS_GD                 \
++   || (r_type) == R_RISCV_TLS_GD_HI16         \
++   || (r_type) == R_RISCV_TLS_GD_LO16)
++
++#define TLS_LDM_RELOC_P(r_type) \
++  ((r_type) == R_RISCV_TLS_LDM                        \
++   || (r_type) == R_RISCV_TLS_LDM_HI16                \
++   || (r_type) == R_RISCV_TLS_LDM_LO16)
++
++/* Structure used to pass information to mips_elf_output_extsym.  */
++
++struct extsym_info
++{
++  bfd *abfd;
++  struct bfd_link_info *info;
++  struct ecoff_debug_info *debug;
++  const struct ecoff_debug_swap *swap;
++  bfd_boolean failed;
++};
++
++/* The structure of the runtime procedure descriptor created by the
++   loader for use by the static exception system.  */
++
++typedef struct runtime_pdr {
++      bfd_vma adr;            /* Memory address of start of procedure.  */
++      long    regmask;        /* Save register mask.  */
++      long    regoffset;      /* Save register offset.  */
++      long    fregmask;       /* Save floating point register mask.  */
++      long    fregoffset;     /* Save floating point register offset.  */
++      long    frameoffset;    /* Frame size.  */
++      short   framereg;       /* Frame pointer register.  */
++      short   pcreg;          /* Offset or reg of return pc.  */
++      long    irpss;          /* Index into the runtime string table.  */
++      long    reserved;
++      struct exception_info *exception_info;/* Pointer to exception array.  */
++} RPDR, *pRPDR;
++#define cbRPDR sizeof (RPDR)
++#define rpdNil ((pRPDR) 0)
++\f
++static struct mips_got_entry *mips_elf_create_local_got_entry
++  (bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long,
++   struct mips_elf_link_hash_entry *, int);
++static bfd_boolean mips_elf_sort_hash_table_f
++  (struct mips_elf_link_hash_entry *, void *);
++static bfd_boolean mips_elf_create_dynamic_relocation
++  (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
++   struct mips_elf_link_hash_entry *, asection *, bfd_vma,
++   bfd_vma *, asection *);
++static hashval_t mips_elf_got_entry_hash
++  (const void *);
++static bfd_vma mips_elf_adjust_gp
++  (bfd *, struct mips_got_info *, bfd *);
++static struct mips_got_info *mips_elf_got_for_ibfd
++  (struct mips_got_info *, bfd *);
++
++/* This will be used when we sort the dynamic relocation records.  */
++static bfd *reldyn_sorting_bfd;
++
++/* True if ABFD is a PIC object.  */
++#define PIC_OBJECT_P(abfd) \
++  ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0)
++
++/* Nonzero if ABFD is using the RV64 ABI.  */
++#define ABI_64_P(abfd) \
++  (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
++
++/* Nonzero if ABFD is using the RV32 ABI.  */
++#define ABI_32_P(abfd) (!ABI_64_P(abfd))
++
++/* The name of the options section.  */
++#define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) ".MIPS.options"
++
++/* True if NAME is the recognized name of any SHT_MIPS_OPTIONS section.
++   Some IRIX system files do not use MIPS_ELF_OPTIONS_SECTION_NAME.  */
++#define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
++  (strcmp (NAME, ".MIPS.options") == 0)
++
++/* Whether the section is readonly.  */
++#define MIPS_ELF_READONLY_SECTION(sec) \
++  ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))               \
++   == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
++
++/* The name of the stub section.  */
++#define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs"
++
++/* The size of an external REL relocation.  */
++#define MIPS_ELF_REL_SIZE(abfd) \
++  (get_elf_backend_data (abfd)->s->sizeof_rel)
++
++/* The size of an external dynamic table entry.  */
++#define MIPS_ELF_DYN_SIZE(abfd) \
++  (get_elf_backend_data (abfd)->s->sizeof_dyn)
++
++/* The size of a GOT entry.  */
++#define MIPS_ELF_GOT_SIZE(abfd) \
++  (get_elf_backend_data (abfd)->s->arch_size / 8)
++
++/* The size of a symbol-table entry.  */
++#define MIPS_ELF_SYM_SIZE(abfd) \
++  (get_elf_backend_data (abfd)->s->sizeof_sym)
++
++/* The default alignment for sections, as a power of two.  */
++#define MIPS_ELF_LOG_FILE_ALIGN(abfd)                         \
++  (get_elf_backend_data (abfd)->s->log_file_align)
++
++/* Get word-sized data.  */
++#define MIPS_ELF_GET_WORD(abfd, ptr) \
++  (ABI_64_P (abfd) ? bfd_get_64 (abfd, ptr) : bfd_get_32 (abfd, ptr))
++
++/* Put out word-sized data.  */
++#define MIPS_ELF_PUT_WORD(abfd, val, ptr)     \
++  (ABI_64_P (abfd)                            \
++   ? bfd_put_64 (abfd, val, ptr)              \
++   : bfd_put_32 (abfd, val, ptr))
++
++/* Add a dynamic symbol table-entry.  */
++#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val)    \
++  _bfd_elf_add_dynamic_entry (info, tag, val)
++
++#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                    \
++  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
++
++/* The name of the dynamic relocation section.  */
++#define MIPS_ELF_REL_DYN_NAME(INFO) ".rel.dyn"
++
++/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
++   from smaller values.  Start with zero, widen, *then* decrement.  */
++#define MINUS_ONE     (((bfd_vma)0) - 1)
++#define MINUS_TWO     (((bfd_vma)0) - 2)
++
++/* The value to write into got[1] for SVR4 targets, to identify it is
++   a GNU object.  The dynamic linker can then use got[1] to store the
++   module pointer.  */
++#define MIPS_ELF_GNU_GOT1_MASK(abfd) \
++  ((bfd_vma) 1 << (ABI_64_P (abfd) ? 63 : 31))
++
++/* The offset of $gp from the beginning of the .got section.  */
++#define ELF_MIPS_GP_OFFSET(INFO) 0x7f0
++
++/* The maximum size of the GOT for it to be addressable using 16-bit
++   offsets from $gp.  */
++#define MIPS_ELF_GOT_MAX_SIZE(INFO) (ELF_MIPS_GP_OFFSET (INFO) + 0x7ff)
++
++#define MIPS_FUNCTION_STUB_NORMAL_SIZE 16
++#define MIPS_FUNCTION_STUB_BIG_SIZE 20
++
++/* The name of the dynamic interpreter.  This is put in the .interp
++   section.  */
++
++#define ELF_DYNAMIC_INTERPRETER(abfd)                 \
++   (ABI_64_P (abfd) ? "/usr/lib64/libc.so.1"  \
++    : "/usr/lib/libc.so.1")
++
++#ifdef BFD64
++#define MNAME(bfd,pre,pos) \
++  (ABI_64_P (bfd) ? CONCAT4 (pre,64,_,pos) : CONCAT4 (pre,32,_,pos))
++#define ELF_R_SYM(bfd, i)                                     \
++  (ABI_64_P (bfd) ? ELF64_R_SYM (i) : ELF32_R_SYM (i))
++#define ELF_R_TYPE(bfd, i)                                    \
++  (ABI_64_P (bfd) ? ELF64_MIPS_R_TYPE (i) : ELF32_R_TYPE (i))
++#define ELF_R_INFO(bfd, s, t)                                 \
++  (ABI_64_P (bfd) ? ELF64_R_INFO (s, t) : ELF32_R_INFO (s, t))
++#else
++#define MNAME(bfd,pre,pos) CONCAT4 (pre,32,_,pos)
++#define ELF_R_SYM(bfd, i)                                     \
++  (ELF32_R_SYM (i))
++#define ELF_R_TYPE(bfd, i)                                    \
++  (ELF32_R_TYPE (i))
++#define ELF_R_INFO(bfd, s, t)                                 \
++  (ELF32_R_INFO (s, t))
++#endif
++
++#define MATCH_LREG(abfd) (ABI_64_P(abfd) ? MATCH_LD : MATCH_LW)
++
++/* The format of the first PLT entry.  */
++
++#define RISCV_PLT0_ENTRY_INSNS 8
++static void
++riscv_make_plt0_entry(bfd* abfd, bfd_vma gotplt_value,
++                      bfd_vma entry[RISCV_PLT0_ENTRY_INSNS])
++{
++  /* lui    t5, %hi(GOTPLT)
++     l[w|d] t7, %lo(GOTPLT)(t5)
++     addi   t5, t5, %lo(GOTPLT)
++     sub    t6, t6, t5
++     move   t5, ra
++     srli   t6, t6, (RV32 ? 2 : 3)
++     addi   t6, t6, -2
++     jalr   t7
++  */
++
++  entry[0] = RISCV_LTYPE(LUI, 17, RISCV_LUI_HIGH_PART(gotplt_value));
++  entry[1] = RISCV_ITYPE(LREG(abfd),  19, 17, RISCV_CONST_LOW_PART(gotplt_value));
++  entry[2] = RISCV_ITYPE(ADDI, 17, 17, RISCV_CONST_LOW_PART(gotplt_value));
++  entry[3] = RISCV_RTYPE(SUB, 18, 18, 17);
++  entry[4] = RISCV_ITYPE(ADDI, 17, LINK_REG, 0);
++  entry[5] = RISCV_ITYPE(SRLI, 18, 18, ABI_64_P(abfd) ? 3 : 2);
++  entry[6] = RISCV_ITYPE(ADDI, 18, 18, -2);
++  entry[7] = RISCV_ITYPE(JALR_C, LINK_REG, 19, 0);
++}
++
++/* The format of subsequent PLT entries.  */
++
++#define RISCV_PLT_ENTRY_INSNS 4
++static void
++riscv_make_plt_entry(bfd* abfd, bfd_vma got_address,
++                     bfd_vma entry[RISCV_PLT_ENTRY_INSNS])
++{
++  /* lui    t6, %hi(.got.plt entry)
++     l[w|d] t7, %lo(.got.plt entry)(t6)
++     addi   t6, t6, %lo(.got.plt entry)
++     jr     t7
++  */
++
++  entry[0] = RISCV_LTYPE(LUI, 18, RISCV_LUI_HIGH_PART(got_address));
++  entry[1] = RISCV_ITYPE(LREG(abfd),  19, 18, RISCV_CONST_LOW_PART(got_address));
++  entry[2] = RISCV_ITYPE(ADDI, 18, 18, RISCV_CONST_LOW_PART(got_address));
++  entry[3] = RISCV_ITYPE(JALR_J, 0, 19, 0);
++}
++
++/* Look up an entry in a MIPS ELF linker hash table.  */
++
++#define mips_elf_link_hash_lookup(table, string, create, copy, follow)        \
++  ((struct mips_elf_link_hash_entry *)                                        \
++   elf_link_hash_lookup (&(table)->root, (string), (create),          \
++                       (copy), (follow)))
++
++/* Traverse a MIPS ELF linker hash table.  */
++
++#define mips_elf_link_hash_traverse(table, func, info)                        \
++  (elf_link_hash_traverse                                             \
++   (&(table)->root,                                                   \
++    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),  \
++    (info)))
++
++/* Find the base offsets for thread-local storage in this object,
++   for GD/LD and IE/LE respectively.  */
++
++#define TP_OFFSET 0x7000
++#define DTP_OFFSET 0x8000
++
++static bfd_vma
++dtprel_base (struct bfd_link_info *info)
++{
++  /* If tls_sec is NULL, we should have signalled an error already.  */
++  if (elf_hash_table (info)->tls_sec == NULL)
++    return 0;
++  return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET;
++}
++
++static bfd_vma
++tprel_base (struct bfd_link_info *info)
++{
++  /* If tls_sec is NULL, we should have signalled an error already.  */
++  if (elf_hash_table (info)->tls_sec == NULL)
++    return 0;
++  return elf_hash_table (info)->tls_sec->vma + TP_OFFSET;
++}
++
++/* Create an entry in a MIPS ELF linker hash table.  */
++
++static struct bfd_hash_entry *
++mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
++                          struct bfd_hash_table *table, const char *string)
++{
++  struct mips_elf_link_hash_entry *ret =
++    (struct mips_elf_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 mips_elf_link_hash_entry));
++  if (ret == NULL)
++    return (struct bfd_hash_entry *) ret;
++
++  /* Call the allocation method of the superclass.  */
++  ret = ((struct mips_elf_link_hash_entry *)
++       _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
++                                   table, string));
++  if (ret != NULL)
++    {
++      /* Set local fields.  */
++      memset (&ret->esym, 0, sizeof (EXTR));
++      /* We use -2 as a marker to indicate that the information has
++       not been set.  -1 means there is no associated ifd.  */
++      ret->esym.ifd = -2;
++      ret->la25_stub = 0;
++      ret->possibly_dynamic_relocs = 0;
++      ret->tls_type = GOT_NORMAL;
++      ret->global_got_area = GGA_NONE;
++      ret->got_only_for_calls = TRUE;
++      ret->readonly_reloc = FALSE;
++      ret->has_static_relocs = FALSE;
++      ret->no_fn_stub = FALSE;
++      ret->has_nonpic_branches = FALSE;
++      ret->needs_lazy_stub = FALSE;
++    }
++
++  return (struct bfd_hash_entry *) ret;
++}
++
++bfd_boolean
++_bfd_riscv_elf_new_section_hook (bfd *abfd, asection *sec)
++{
++  if (!sec->used_by_bfd)
++    {
++      struct _mips_elf_section_data *sdata;
++      bfd_size_type amt = sizeof (*sdata);
++
++      sdata = bfd_zalloc (abfd, amt);
++      if (sdata == NULL)
++      return FALSE;
++      sec->used_by_bfd = sdata;
++    }
++
++  return _bfd_elf_new_section_hook (abfd, sec);
++}
++\f
++/* Read ECOFF debugging information from a .mdebug section into a
++   ecoff_debug_info structure.  */
++
++bfd_boolean
++_bfd_riscv_elf_read_ecoff_info (bfd *abfd, asection *section,
++                             struct ecoff_debug_info *debug)
++{
++  HDRR *symhdr;
++  const struct ecoff_debug_swap *swap;
++  char *ext_hdr;
++
++  swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
++  memset (debug, 0, sizeof (*debug));
++
++  ext_hdr = bfd_malloc (swap->external_hdr_size);
++  if (ext_hdr == NULL && swap->external_hdr_size != 0)
++    goto error_return;
++
++  if (! bfd_get_section_contents (abfd, section, ext_hdr, 0,
++                                swap->external_hdr_size))
++    goto error_return;
++
++  symhdr = &debug->symbolic_header;
++  (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr);
++
++  /* The symbolic header contains absolute file offsets and sizes to
++     read.  */
++#define READ(ptr, offset, count, size, type)                          \
++  if (symhdr->count == 0)                                             \
++    debug->ptr = NULL;                                                        \
++  else                                                                        \
++    {                                                                 \
++      bfd_size_type amt = (bfd_size_type) size * symhdr->count;               \
++      debug->ptr = bfd_malloc (amt);                                  \
++      if (debug->ptr == NULL)                                         \
++      goto error_return;                                              \
++      if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0              \
++        || bfd_bread (debug->ptr, amt, abfd) != amt)                  \
++      goto error_return;                                              \
++    }
++
++  READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
++  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *);
++  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *);
++  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *);
++  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *);
++  READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
++      union aux_ext *);
++  READ (ss, cbSsOffset, issMax, sizeof (char), char *);
++  READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
++  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *);
++  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *);
++  READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *);
++#undef READ
++
++  debug->fdr = NULL;
++
++  return TRUE;
++
++ error_return:
++  if (ext_hdr != NULL)
++    free (ext_hdr);
++  if (debug->line != NULL)
++    free (debug->line);
++  if (debug->external_dnr != NULL)
++    free (debug->external_dnr);
++  if (debug->external_pdr != NULL)
++    free (debug->external_pdr);
++  if (debug->external_sym != NULL)
++    free (debug->external_sym);
++  if (debug->external_opt != NULL)
++    free (debug->external_opt);
++  if (debug->external_aux != NULL)
++    free (debug->external_aux);
++  if (debug->ss != NULL)
++    free (debug->ss);
++  if (debug->ssext != NULL)
++    free (debug->ssext);
++  if (debug->external_fdr != NULL)
++    free (debug->external_fdr);
++  if (debug->external_rfd != NULL)
++    free (debug->external_rfd);
++  if (debug->external_ext != NULL)
++    free (debug->external_ext);
++  return FALSE;
++}
++
++/* We're going to create a stub for H.  Create a symbol for the stub's
++   value and size, to help make the disassembly easier to read.  */
++
++static bfd_boolean
++mips_elf_create_stub_symbol (struct bfd_link_info *info,
++                           struct mips_elf_link_hash_entry *h,
++                           const char *prefix, asection *s, bfd_vma value,
++                           bfd_vma size)
++{
++  struct bfd_link_hash_entry *bh;
++  struct elf_link_hash_entry *elfh;
++  const char *name;
++
++  /* Create a new symbol.  */
++  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
++  bh = NULL;
++  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
++                                       BSF_LOCAL, s, value, NULL,
++                                       TRUE, FALSE, &bh))
++    return FALSE;
++
++  /* Make it a local function.  */
++  elfh = (struct elf_link_hash_entry *) bh;
++  elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
++  elfh->size = size;
++  elfh->forced_local = 1;
++  return TRUE;
++}
++
++/* Hashtable callbacks for mips_elf_la25_stubs.  */
++
++static hashval_t
++mips_elf_la25_stub_hash (const void *entry_)
++{
++  const struct mips_elf_la25_stub *entry;
++
++  entry = (struct mips_elf_la25_stub *) entry_;
++  return entry->h->root.root.u.def.section->id
++    + entry->h->root.root.u.def.value;
++}
++
++static int
++mips_elf_la25_stub_eq (const void *entry1_, const void *entry2_)
++{
++  const struct mips_elf_la25_stub *entry1, *entry2;
++
++  entry1 = (struct mips_elf_la25_stub *) entry1_;
++  entry2 = (struct mips_elf_la25_stub *) entry2_;
++  return ((entry1->h->root.root.u.def.section
++         == entry2->h->root.root.u.def.section)
++        && (entry1->h->root.root.u.def.value
++            == entry2->h->root.root.u.def.value));
++}
++
++/* Called by the linker to set up the la25 stub-creation code.  FN is
++   the linker's implementation of add_stub_function.  Return true on
++   success.  */
++
++bfd_boolean
++_bfd_riscv_elf_init_stubs (struct bfd_link_info *info,
++                        asection *(*fn) (const char *, asection *,
++                                         asection *))
++{
++  struct mips_elf_link_hash_table *htab;
++
++  htab = mips_elf_hash_table (info);
++  if (htab == NULL)
++    return FALSE;
++
++  htab->add_stub_section = fn;
++  htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
++                                    mips_elf_la25_stub_eq, NULL);
++  if (htab->la25_stubs == NULL)
++    return FALSE;
++
++  return TRUE;
++}
++
++/* Return true if H is a locally-defined PIC function, in the sense
++   that it might need $25 to be valid on entry.  Note that MIPS16
++   functions never need $25 to be valid on entry; they set up $gp
++   using PC-relative instructions instead.  */
++
++static bfd_boolean
++mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
++{
++  return ((h->root.root.type == bfd_link_hash_defined
++         || h->root.root.type == bfd_link_hash_defweak)
++        && h->root.def_regular
++        && !bfd_is_abs_section (h->root.root.u.def.section)
++        && !ELF_ST_IS_MIPS16 (h->root.other)
++        && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
++            || ELF_ST_IS_MIPS_PIC (h->root.other)));
++}
++
++/* STUB describes an la25 stub that we have decided to implement
++   by inserting an LUI/ADDIU pair before the target function.
++   Create the section and redirect the function symbol to it.  */
++
++static bfd_boolean
++mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
++                       struct bfd_link_info *info)
++{
++  struct mips_elf_link_hash_table *htab;
++  char *name;
++  asection *s, *input_section;
++  unsigned int align;
++
++  htab = mips_elf_hash_table (info);
++  if (htab == NULL)
++    return FALSE;
++
++  /* Create a unique name for the new section.  */
++  name = bfd_malloc (11 + sizeof (".text.stub."));
++  if (name == NULL)
++    return FALSE;
++  sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
++
++  /* Create the section.  */
++  input_section = stub->h->root.root.u.def.section;
++  s = htab->add_stub_section (name, input_section,
++                            input_section->output_section);
++  if (s == NULL)
++    return FALSE;
++
++  /* Make sure that any padding goes before the stub.  */
++  align = input_section->alignment_power;
++  if (!bfd_set_section_alignment (s->owner, s, align))
++    return FALSE;
++  if (align > 3)
++    s->size = (1 << align) - 8;
++
++  /* Create a symbol for the stub.  */
++  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
++  stub->stub_section = s;
++  stub->offset = s->size;
++
++  /* Allocate room for it.  */
++  s->size += 8;
++  return TRUE;
++}
++
++/* STUB describes an la25 stub that we have decided to implement
++   with a separate trampoline.  Allocate room for it and redirect
++   the function symbol to it.  */
++
++static bfd_boolean
++mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
++                            struct bfd_link_info *info)
++{
++  struct mips_elf_link_hash_table *htab;
++  asection *s;
++
++  htab = mips_elf_hash_table (info);
++  if (htab == NULL)
++    return FALSE;
++
++  /* Create a trampoline section, if we haven't already.  */
++  s = htab->strampoline;
++  if (s == NULL)
++    {
++      asection *input_section = stub->h->root.root.u.def.section;
++      s = htab->add_stub_section (".text", NULL,
++                                input_section->output_section);
++      if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
++      return FALSE;
++      htab->strampoline = s;
++    }
++
++  /* Create a symbol for the stub.  */
++  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 16);
++  stub->stub_section = s;
++  stub->offset = s->size;
++
++  /* Allocate room for it.  */
++  s->size += 16;
++  return TRUE;
++}
++
++/* H describes a symbol that needs an la25 stub.  Make sure that an
++   appropriate stub exists and point H at it.  */
++
++static bfd_boolean
++mips_elf_add_la25_stub (struct bfd_link_info *info,
++                      struct mips_elf_link_hash_entry *h)
++{
++  struct mips_elf_link_hash_table *htab;
++  struct mips_elf_la25_stub search, *stub;
++  bfd_boolean use_trampoline_p;
++  asection *s;
++  bfd_vma value;
++  void **slot;
++
++  /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
++     of the section and if we would need no more than 2 nops.  */
++  s = h->root.root.u.def.section;
++  value = h->root.root.u.def.value;
++  use_trampoline_p = (value != 0 || s->alignment_power > 4);
++
++  /* Describe the stub we want.  */
++  search.stub_section = NULL;
++  search.offset = 0;
++  search.h = h;
++
++  /* See if we've already created an equivalent stub.  */
++  htab = mips_elf_hash_table (info);
++  if (htab == NULL)
++    return FALSE;
++
++  slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
++  if (slot == NULL)
++    return FALSE;
++
++  stub = (struct mips_elf_la25_stub *) *slot;
++  if (stub != NULL)
++    {
++      /* We can reuse the existing stub.  */
++      h->la25_stub = stub;
++      return TRUE;
++    }
++
++  /* Create a permanent copy of ENTRY and add it to the hash table.  */
++  stub = bfd_malloc (sizeof (search));
++  if (stub == NULL)
++    return FALSE;
++  *stub = search;
++  *slot = stub;
++
++  h->la25_stub = stub;
++  return (use_trampoline_p
++        ? mips_elf_add_la25_trampoline (stub, info)
++        : mips_elf_add_la25_intro (stub, info));
++}
++
++/* A mips_elf_link_hash_traverse callback that is called before sizing
++   sections.  DATA points to a mips_htab_traverse_info structure.  */
++
++static bfd_boolean
++mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
++{
++  struct mips_htab_traverse_info *hti;
++
++  hti = (struct mips_htab_traverse_info *) data;
++  if (h->root.root.type == bfd_link_hash_warning)
++    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
++
++  if (mips_elf_local_pic_function_p (h))
++    {
++      /* H is a function that might need $25 to be valid on entry.
++       If we're creating a non-PIC relocatable object, mark H as
++       being PIC.  If we're creating a non-relocatable object with
++       non-PIC branches and jumps to H, make sure that H has an la25
++       stub.  */
++      if (hti->info->relocatable)
++      {
++        if (!PIC_OBJECT_P (hti->output_bfd))
++          h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other);
++      }
++      else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h))
++      {
++        hti->error = TRUE;
++        return FALSE;
++      }
++    }
++  return TRUE;
++}
++\f
++
++static inline bfd_boolean
++got16_reloc_p (int r_type)
++{
++  return r_type == R_RISCV_GOT16;
++}
++
++static inline bfd_boolean
++call16_reloc_p (int r_type)
++{
++  return r_type == R_RISCV_CALL16;
++}
++
++static inline bfd_boolean
++hi16_reloc_p (int r_type)
++{
++  return r_type == R_RISCV_HI16;
++}
++
++static inline bfd_boolean
++lo16_reloc_p (int r_type)
++{
++  return r_type == R_RISCV_LO16;
++}
++
++static bfd_vma
++mips_elf_high (bfd_vma value)
++{
++  return RISCV_LUI_HIGH_PART (value) & ((1<<RISCV_BIGIMM_BITS)-1);
++}
++
++bfd_reloc_status_type
++_bfd_riscv_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
++                             arelent *reloc_entry, asection *input_section,
++                             bfd_boolean relocatable, void *data, bfd_vma gp)
++{
++  bfd_vma relocation;
++  bfd_signed_vma val;
++  bfd_reloc_status_type status;
++
++  if (bfd_is_com_section (symbol->section))
++    relocation = 0;
++  else
++    relocation = symbol->value;
++
++  relocation += symbol->section->output_section->vma;
++  relocation += symbol->section->output_offset;
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  /* Set val to the offset into the section or symbol.  */
++  val = reloc_entry->addend;
++
++  _bfd_riscv_elf_sign_extend (val, RISCV_IMM_BITS);
++
++  /* Adjust val for the final section location and GP value.  If we
++     are producing relocatable output, we don't want to do this for
++     an external symbol.  */
++  if (! relocatable
++      || (symbol->flags & BSF_SECTION_SYM) != 0)
++    val += relocation - gp;
++
++  if (reloc_entry->howto->partial_inplace)
++    {
++      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
++                                     (bfd_byte *) data
++                                     + reloc_entry->address);
++      if (status != bfd_reloc_ok)
++      return status;
++    }
++  else
++    reloc_entry->addend = val;
++
++  if (relocatable)
++    reloc_entry->address += input_section->output_offset;
++
++  return bfd_reloc_ok;
++}
++
++/* Used to store a REL high-part relocation such as R_RISCV_HI16 or
++   R_RISCV_GOT16.  REL is the relocation, INPUT_SECTION is the section
++   that contains the relocation field and DATA points to the start of
++   INPUT_SECTION.  */
++
++struct mips_hi16
++{
++  struct mips_hi16 *next;
++  bfd_byte *data;
++  asection *input_section;
++  arelent rel;
++};
++
++/* FIXME: This should not be a static variable.  */
++
++static struct mips_hi16 *mips_hi16_list;
++
++/* A howto special_function for REL *HI16 relocations.  We can only
++   calculate the correct value once we've seen the partnering
++   *LO16 relocation, so just save the information for later.
++
++   The ABI requires that the *LO16 immediately follow the *HI16.
++   However, as a GNU extension, we permit an arbitrary number of
++   *HI16s to be associated with a single *LO16.  This significantly
++   simplies the relocation handling in gcc.  */
++
++bfd_reloc_status_type
++_bfd_riscv_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
++                        asymbol *symbol ATTRIBUTE_UNUSED, void *data,
++                        asection *input_section, bfd *output_bfd,
++                        char **error_message ATTRIBUTE_UNUSED)
++{
++  struct mips_hi16 *n;
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  n = bfd_malloc (sizeof *n);
++  if (n == NULL)
++    return bfd_reloc_outofrange;
++
++  n->next = mips_hi16_list;
++  n->data = data;
++  n->input_section = input_section;
++  n->rel = *reloc_entry;
++  mips_hi16_list = n;
++
++  if (output_bfd != NULL)
++    reloc_entry->address += input_section->output_offset;
++
++  return bfd_reloc_ok;
++}
++
++/* A howto special_function for REL R_MIPS*_GOT16 relocations.  This is just
++   like any other 16-bit relocation when applied to global symbols, but is
++   treated in the same as R_RISCV_HI16 when applied to local symbols.  */
++
++bfd_reloc_status_type
++_bfd_riscv_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                         void *data, asection *input_section,
++                         bfd *output_bfd, char **error_message)
++{
++  if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
++      || bfd_is_und_section (bfd_get_section (symbol))
++      || bfd_is_com_section (bfd_get_section (symbol)))
++    /* The relocation is against a global symbol.  */
++    return _bfd_riscv_elf_generic_reloc (abfd, reloc_entry, symbol, data,
++                                      input_section, output_bfd,
++                                      error_message);
++
++  return _bfd_riscv_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
++                                 input_section, output_bfd, error_message);
++}
++
++/* A howto special_function for REL *LO16 relocations.  The *LO16 itself
++   is a straightforward 16 bit inplace relocation, but we must deal with
++   any partnering high-part relocations as well.  */
++
++bfd_reloc_status_type
++_bfd_riscv_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
++                        void *data, asection *input_section,
++                        bfd *output_bfd, char **error_message)
++{
++  bfd_vma vallo;
++  bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  vallo = bfd_get_32 (abfd, location);
++
++  while (mips_hi16_list != NULL)
++    {
++      bfd_reloc_status_type ret;
++      struct mips_hi16 *hi;
++
++      hi = mips_hi16_list;
++
++      /* R_MIPS*_GOT16 relocations are something of a special case.  We
++       want to install the addend in the same way as for a R_MIPS*_HI16
++       relocation (with a rightshift of 16).  However, since GOT16
++       relocations can also be used with global symbols, their howto
++       has a rightshift of 0.  */
++      if (hi->rel.howto->type == R_RISCV_GOT16)
++      hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_RISCV_HI16, FALSE);
++
++      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
++       carry or borrow will induce a change of +1 or -1 in the high part.  */
++      hi->rel.addend += (vallo + RISCV_IMM_REACH/2) & (RISCV_IMM_REACH-1);
++
++      ret = _bfd_riscv_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data,
++                                       hi->input_section, output_bfd,
++                                       error_message);
++      if (ret != bfd_reloc_ok)
++      return ret;
++
++      mips_hi16_list = hi->next;
++      free (hi);
++    }
++
++  return _bfd_riscv_elf_generic_reloc (abfd, reloc_entry, symbol, data,
++                                    input_section, output_bfd,
++                                    error_message);
++}
++
++/* A generic howto special_function.  This calculates and installs the
++   relocation itself, thus avoiding the oft-discussed problems in
++   bfd_perform_relocation and bfd_install_relocation.  */
++
++bfd_reloc_status_type
++_bfd_riscv_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
++                           asymbol *symbol, void *data ATTRIBUTE_UNUSED,
++                           asection *input_section, bfd *output_bfd,
++                           char **error_message ATTRIBUTE_UNUSED)
++{
++  bfd_signed_vma val;
++  bfd_reloc_status_type status;
++  bfd_boolean relocatable;
++
++  relocatable = (output_bfd != NULL);
++
++  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
++    return bfd_reloc_outofrange;
++
++  /* Build up the field adjustment in VAL.  */
++  val = 0;
++  if (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)
++    {
++      /* Either we're calculating the final field value or we have a
++       relocation against a section symbol.  Add in the section's
++       offset or address.  */
++      val += symbol->section->output_section->vma;
++      val += symbol->section->output_offset;
++    }
++
++  if (!relocatable)
++    {
++      /* We're calculating the final field value.  Add in the symbol's value
++       and, if pc-relative, subtract the address of the field itself.  */
++      val += symbol->value;
++      if (reloc_entry->howto->pc_relative)
++      {
++        val -= input_section->output_section->vma;
++        val -= input_section->output_offset;
++        val -= reloc_entry->address;
++      }
++    }
++
++  /* VAL is now the final adjustment.  If we're keeping this relocation
++     in the output file, and if the relocation uses a separate addend,
++     we just need to add VAL to that addend.  Otherwise we need to add
++     VAL to the relocation field itself.  */
++  if (relocatable && !reloc_entry->howto->partial_inplace)
++    reloc_entry->addend += val;
++  else
++    {
++      bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
++
++      /* Add in the separate addend, if any.  */
++      val += reloc_entry->addend;
++
++      /* Add VAL to the relocation field.  */
++      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
++                                     location);
++
++      if (status != bfd_reloc_ok)
++      return status;
++    }
++
++  if (relocatable)
++    reloc_entry->address += input_section->output_offset;
++
++  return bfd_reloc_ok;
++}
++
++/* A .reginfo section holds a single Elf32_RegInfo structure.  These
++   routines swap this structure in and out.  They are used outside of
++   BFD, so they are globally visible.  */
++
++void
++bfd_riscv_elf32_swap_reginfo_in (bfd *abfd, const Elf32_External_RegInfo *ex,
++                              Elf32_RegInfo *in)
++{
++  in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask);
++  in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]);
++  in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]);
++  in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]);
++  in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]);
++  in->ri_gp_value = H_GET_32 (abfd, ex->ri_gp_value);
++}
++
++void
++bfd_riscv_elf32_swap_reginfo_out (bfd *abfd, const Elf32_RegInfo *in,
++                               Elf32_External_RegInfo *ex)
++{
++  H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask);
++  H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]);
++  H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]);
++  H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]);
++  H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]);
++  H_PUT_32 (abfd, in->ri_gp_value, ex->ri_gp_value);
++}
++
++/* In the 64 bit ABI, the .MIPS.options section holds register
++   information in an Elf64_Reginfo structure.  These routines swap
++   them in and out.  They are globally visible because they are used
++   outside of BFD.  These routines are here so that gas can call them
++   without worrying about whether the 64 bit ABI has been included.  */
++
++void
++bfd_riscv_elf64_swap_reginfo_in (bfd *abfd, const Elf64_External_RegInfo *ex,
++                              Elf64_Internal_RegInfo *in)
++{
++  in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask);
++  in->ri_pad = H_GET_32 (abfd, ex->ri_pad);
++  in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]);
++  in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]);
++  in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]);
++  in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]);
++  in->ri_gp_value = H_GET_64 (abfd, ex->ri_gp_value);
++}
++
++void
++bfd_riscv_elf64_swap_reginfo_out (bfd *abfd, const Elf64_Internal_RegInfo *in,
++                               Elf64_External_RegInfo *ex)
++{
++  H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask);
++  H_PUT_32 (abfd, in->ri_pad, ex->ri_pad);
++  H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]);
++  H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]);
++  H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]);
++  H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]);
++  H_PUT_64 (abfd, in->ri_gp_value, ex->ri_gp_value);
++}
++
++/* Swap in an options header.  */
++
++void
++bfd_riscv_elf_swap_options_in (bfd *abfd, const Elf_External_Options *ex,
++                            Elf_Internal_Options *in)
++{
++  in->kind = H_GET_8 (abfd, ex->kind);
++  in->size = H_GET_8 (abfd, ex->size);
++  in->section = H_GET_16 (abfd, ex->section);
++  in->info = H_GET_32 (abfd, ex->info);
++}
++
++/* Swap out an options header.  */
++
++void
++bfd_riscv_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in,
++                             Elf_External_Options *ex)
++{
++  H_PUT_8 (abfd, in->kind, ex->kind);
++  H_PUT_8 (abfd, in->size, ex->size);
++  H_PUT_16 (abfd, in->section, ex->section);
++  H_PUT_32 (abfd, in->info, ex->info);
++}
++\f
++/* This function is called via qsort() to sort the dynamic relocation
++   entries by increasing r_symndx value.  */
++
++static int
++sort_dynamic_relocs (const void *arg1, const void *arg2)
++{
++  Elf_Internal_Rela int_reloc1;
++  Elf_Internal_Rela int_reloc2;
++  int diff;
++
++  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
++  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
++
++  diff = ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info);
++  if (diff != 0)
++    return diff;
++
++  if (int_reloc1.r_offset < int_reloc2.r_offset)
++    return -1;
++  if (int_reloc1.r_offset > int_reloc2.r_offset)
++    return 1;
++  return 0;
++}
++
++/* Like sort_dynamic_relocs, but used for elf64 relocations.  */
++
++static int
++sort_dynamic_relocs_64 (const void *arg1 ATTRIBUTE_UNUSED,
++                      const void *arg2 ATTRIBUTE_UNUSED)
++{
++#ifdef BFD64
++  Elf_Internal_Rela int_reloc1[3];
++  Elf_Internal_Rela int_reloc2[3];
++
++  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
++    (reldyn_sorting_bfd, arg1, int_reloc1);
++  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
++    (reldyn_sorting_bfd, arg2, int_reloc2);
++
++  if (ELF64_R_SYM (int_reloc1[0].r_info) < ELF64_R_SYM (int_reloc2[0].r_info))
++    return -1;
++  if (ELF64_R_SYM (int_reloc1[0].r_info) > ELF64_R_SYM (int_reloc2[0].r_info))
++    return 1;
++
++  if (int_reloc1[0].r_offset < int_reloc2[0].r_offset)
++    return -1;
++  if (int_reloc1[0].r_offset > int_reloc2[0].r_offset)
++    return 1;
++  return 0;
++#else
++  abort ();
++#endif
++}
++
++
++/* This routine is used to write out ECOFF debugging external symbol
++   information.  It is called via mips_elf_link_hash_traverse.  The
++   ECOFF external symbol information must match the ELF external
++   symbol information.  Unfortunately, at this point we don't know
++   whether a symbol is required by reloc information, so the two
++   tables may wind up being different.  We must sort out the external
++   symbol information before we can set the final size of the .mdebug
++   section, and we must set the size of the .mdebug section before we
++   can relocate any sections, and we can't know which symbols are
++   required by relocation until we relocate the sections.
++   Fortunately, it is relatively unlikely that any symbol will be
++   stripped but required by a reloc.  In particular, it can not happen
++   when generating a final executable.  */
++
++static bfd_boolean
++mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
++{
++  struct extsym_info *einfo = data;
++  bfd_boolean strip;
++  asection *sec, *output_section;
++
++  if (h->root.root.type == bfd_link_hash_warning)
++    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
++
++  if (h->root.indx == -2)
++    strip = FALSE;
++  else if ((h->root.def_dynamic
++          || h->root.ref_dynamic
++          || h->root.type == bfd_link_hash_new)
++         && !h->root.def_regular
++         && !h->root.ref_regular)
++    strip = TRUE;
++  else if (einfo->info->strip == strip_all
++         || (einfo->info->strip == strip_some
++             && bfd_hash_lookup (einfo->info->keep_hash,
++                                 h->root.root.root.string,
++                                 FALSE, FALSE) == NULL))
++    strip = TRUE;
++  else
++    strip = FALSE;
++
++  if (strip)
++    return TRUE;
++
++  if (h->esym.ifd == -2)
++    {
++      h->esym.jmptbl = 0;
++      h->esym.cobol_main = 0;
++      h->esym.weakext = 0;
++      h->esym.reserved = 0;
++      h->esym.ifd = ifdNil;
++      h->esym.asym.value = 0;
++      h->esym.asym.st = stGlobal;
++
++      if (h->root.root.type == bfd_link_hash_undefined
++        || h->root.root.type == bfd_link_hash_undefweak)
++      h->esym.asym.sc = scUndefined;
++      else if (h->root.root.type != bfd_link_hash_defined
++        && h->root.root.type != bfd_link_hash_defweak)
++      h->esym.asym.sc = scAbs;
++      else
++      {
++        const char *name;
++
++        sec = h->root.root.u.def.section;
++        output_section = sec->output_section;
++
++        /* When making a shared library and symbol h is the one from
++           the another shared library, OUTPUT_SECTION may be null.  */
++        if (output_section == NULL)
++          h->esym.asym.sc = scUndefined;
++        else
++          {
++            name = bfd_section_name (output_section->owner, output_section);
++
++            if (strcmp (name, ".text") == 0)
++              h->esym.asym.sc = scText;
++            else if (strcmp (name, ".data") == 0)
++              h->esym.asym.sc = scData;
++            else if (strcmp (name, ".sdata") == 0)
++              h->esym.asym.sc = scSData;
++            else if (strcmp (name, ".rodata") == 0
++                     || strcmp (name, ".rdata") == 0)
++              h->esym.asym.sc = scRData;
++            else if (strcmp (name, ".bss") == 0)
++              h->esym.asym.sc = scBss;
++            else if (strcmp (name, ".sbss") == 0)
++              h->esym.asym.sc = scSBss;
++            else if (strcmp (name, ".init") == 0)
++              h->esym.asym.sc = scInit;
++            else if (strcmp (name, ".fini") == 0)
++              h->esym.asym.sc = scFini;
++            else
++              h->esym.asym.sc = scAbs;
++          }
++      }
++
++      h->esym.asym.reserved = 0;
++      h->esym.asym.index = indexNil;
++    }
++
++  if (h->root.root.type == bfd_link_hash_common)
++    h->esym.asym.value = h->root.root.u.c.size;
++  else if (h->root.root.type == bfd_link_hash_defined
++         || h->root.root.type == bfd_link_hash_defweak)
++    {
++      if (h->esym.asym.sc == scCommon)
++      h->esym.asym.sc = scBss;
++      else if (h->esym.asym.sc == scSCommon)
++      h->esym.asym.sc = scSBss;
++
++      sec = h->root.root.u.def.section;
++      output_section = sec->output_section;
++      if (output_section != NULL)
++      h->esym.asym.value = (h->root.root.u.def.value
++                            + sec->output_offset
++                            + output_section->vma);
++      else
++      h->esym.asym.value = 0;
++    }
++  else
++    {
++      struct mips_elf_link_hash_entry *hd = h;
++
++      while (hd->root.root.type == bfd_link_hash_indirect)
++      hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
++
++      if (hd->needs_lazy_stub)
++      {
++        /* Set type and value for a symbol with a function stub.  */
++        h->esym.asym.st = stProc;
++        sec = hd->root.root.u.def.section;
++        if (sec == NULL)
++          h->esym.asym.value = 0;
++        else
++          {
++            output_section = sec->output_section;
++            if (output_section != NULL)
++              h->esym.asym.value = (hd->root.plt.offset
++                                    + sec->output_offset
++                                    + output_section->vma);
++            else
++              h->esym.asym.value = 0;
++          }
++      }
++    }
++
++  if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
++                                    h->root.root.root.string,
++                                    &h->esym))
++    {
++      einfo->failed = TRUE;
++      return FALSE;
++    }
++
++  return TRUE;
++}
++
++/* Functions to manage the got entry hash table.  */
++
++/* Use all 64 bits of a bfd_vma for the computation of a 32-bit
++   hash number.  */
++
++static INLINE hashval_t
++mips_elf_hash_bfd_vma (bfd_vma addr)
++{
++#ifdef BFD64
++  return addr + (addr >> 32);
++#else
++  return addr;
++#endif
++}
++
++/* got_entries only match if they're identical, except for gotidx, so
++   use all fields to compute the hash, and compare the appropriate
++   union members.  */
++
++static hashval_t
++mips_elf_got_entry_hash (const void *entry_)
++{
++  const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
++
++  return entry->symndx
++    + ((entry->tls_type & GOT_TLS_LDM) << 17)
++    + (! entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
++       : entry->abfd->id
++         + (entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend)
++          : entry->d.h->root.root.root.hash));
++}
++
++static int
++mips_elf_got_entry_eq (const void *entry1, const void *entry2)
++{
++  const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
++  const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
++
++  /* An LDM entry can only match another LDM entry.  */
++  if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
++    return 0;
++
++  return e1->abfd == e2->abfd && e1->symndx == e2->symndx
++    && (! e1->abfd ? e1->d.address == e2->d.address
++      : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
++      : e1->d.h == e2->d.h);
++}
++
++/* multi_got_entries are still a match in the case of global objects,
++   even if the input bfd in which they're referenced differs, so the
++   hash computation and compare functions are adjusted
++   accordingly.  */
++
++static hashval_t
++mips_elf_multi_got_entry_hash (const void *entry_)
++{
++  const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
++
++  return entry->symndx
++    + (! entry->abfd
++       ? mips_elf_hash_bfd_vma (entry->d.address)
++       : entry->symndx >= 0
++       ? ((entry->tls_type & GOT_TLS_LDM)
++        ? (GOT_TLS_LDM << 17)
++        : (entry->abfd->id
++           + mips_elf_hash_bfd_vma (entry->d.addend)))
++       : entry->d.h->root.root.root.hash);
++}
++
++static int
++mips_elf_multi_got_entry_eq (const void *entry1, const void *entry2)
++{
++  const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
++  const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
++
++  /* Any two LDM entries match.  */
++  if (e1->tls_type & e2->tls_type & GOT_TLS_LDM)
++    return 1;
++
++  /* Nothing else matches an LDM entry.  */
++  if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
++    return 0;
++
++  return e1->symndx == e2->symndx
++    && (e1->symndx >= 0 ? e1->abfd == e2->abfd && e1->d.addend == e2->d.addend
++      : e1->abfd == NULL || e2->abfd == NULL
++      ? e1->abfd == e2->abfd && e1->d.address == e2->d.address
++      : e1->d.h == e2->d.h);
++}
++
++static hashval_t
++mips_got_page_entry_hash (const void *entry_)
++{
++  const struct mips_got_page_entry *entry;
++
++  entry = (const struct mips_got_page_entry *) entry_;
++  return entry->abfd->id + entry->symndx;
++}
++
++static int
++mips_got_page_entry_eq (const void *entry1_, const void *entry2_)
++{
++  const struct mips_got_page_entry *entry1, *entry2;
++
++  entry1 = (const struct mips_got_page_entry *) entry1_;
++  entry2 = (const struct mips_got_page_entry *) entry2_;
++  return entry1->abfd == entry2->abfd && entry1->symndx == entry2->symndx;
++}
++\f
++/* Return the dynamic relocation section.  If it doesn't exist, try to
++   create a new it if CREATE_P, otherwise return NULL.  Also return NULL
++   if creation fails.  */
++
++static asection *
++mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p)
++{
++  const char *dname;
++  asection *sreloc;
++  bfd *dynobj;
++
++  dname = MIPS_ELF_REL_DYN_NAME (info);
++  dynobj = elf_hash_table (info)->dynobj;
++  sreloc = bfd_get_section_by_name (dynobj, dname);
++  if (sreloc == NULL && create_p)
++    {
++      sreloc = bfd_make_section_with_flags (dynobj, dname,
++                                          (SEC_ALLOC
++                                           | SEC_LOAD
++                                           | SEC_HAS_CONTENTS
++                                           | SEC_IN_MEMORY
++                                           | SEC_LINKER_CREATED
++                                           | SEC_READONLY));
++      if (sreloc == NULL
++        || ! bfd_set_section_alignment (dynobj, sreloc,
++                                        MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
++      return NULL;
++    }
++  return sreloc;
++}
++
++/* Count the number of relocations needed for a TLS GOT entry, with
++   access types from TLS_TYPE, and symbol H (or a local symbol if H
++   is NULL).  */
++
++static int
++mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
++                   struct elf_link_hash_entry *h)
++{
++  int indx = 0;
++  int ret = 0;
++  bfd_boolean need_relocs = FALSE;
++  bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
++
++  if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
++      && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h)))
++    indx = h->dynindx;
++
++  if ((info->shared || indx != 0)
++      &