Files
meta-riscv/recipes-devtool/riscv-tools/files/binutils-2.21.1-riscv.patch
2017-10-06 20:56:51 -07:00

14052 lines
483 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/binutils-2.21.1/bfd/archures.c b/binutils-2.21.1/bfd/archures.c
index 1867154..ae47b0c 100644
--- a/binutils-2.21.1/bfd/archures.c
+++ binutils-2.21.1/bfd/archures.c
@@ -515,6 +515,7 @@ extern const bfd_arch_info_type bfd_pj_arch;
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 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
&bfd_or32_arch,
&bfd_pdp11_arch,
&bfd_powerpc_arch,
+ &bfd_riscv_arch,
&bfd_rs6000_arch,
&bfd_rx_arch,
&bfd_s390_arch,
diff --git a/binutils-2.21.1/bfd/bfd-in2.h b/binutils-2.21.1/bfd/bfd-in2.h
index 59b1b8f..25dc423 100644
--- a/binutils-2.21.1/bfd/bfd-in2.h
+++ binutils-2.21.1/bfd/bfd-in2.h
@@ -1919,6 +1919,9 @@ enum bfd_architecture
#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_riscv32 132
+#define bfd_mach_riscv64 164
bfd_arch_rs6000, /* IBM RS/6000 */
#define bfd_mach_rs6k 6000
#define bfd_mach_rs6k_rs1 6001
@@ -4761,6 +4764,38 @@ relative offset from _GLOBAL_OFFSET_TABLE_ */
value in a word. The relocation is relative offset from */
BFD_RELOC_MICROBLAZE_32_GOTOFF,
+ /* RISC-V relocations */
+ BFD_RELOC_RISCV_HI20,
+ BFD_RELOC_RISCV_PCREL_HI20,
+ BFD_RELOC_RISCV_PCREL_LO12_I,
+ BFD_RELOC_RISCV_PCREL_LO12_S,
+ BFD_RELOC_RISCV_LO12_I,
+ BFD_RELOC_RISCV_LO12_S,
+ BFD_RELOC_RISCV_GPREL12_I,
+ BFD_RELOC_RISCV_GPREL12_S,
+ BFD_RELOC_RISCV_TPREL_HI20,
+ BFD_RELOC_RISCV_TPREL_LO12_I,
+ BFD_RELOC_RISCV_TPREL_LO12_S,
+ BFD_RELOC_RISCV_TPREL_ADD,
+ BFD_RELOC_RISCV_CALL,
+ BFD_RELOC_RISCV_CALL_PLT,
+ BFD_RELOC_RISCV_ADD32,
+ BFD_RELOC_RISCV_ADD64,
+ BFD_RELOC_RISCV_SUB32,
+ BFD_RELOC_RISCV_SUB64,
+ BFD_RELOC_RISCV_GOT_HI20,
+ BFD_RELOC_RISCV_GOT_LO12,
+ BFD_RELOC_RISCV_TLS_GOT_HI20,
+ BFD_RELOC_RISCV_TLS_GOT_LO12,
+ BFD_RELOC_RISCV_TLS_IE_HI20,
+ BFD_RELOC_RISCV_TLS_IE_LO12,
+ BFD_RELOC_RISCV_TLS_IE_ADD,
+ BFD_RELOC_RISCV_TLS_IE_LO12_I,
+ BFD_RELOC_RISCV_TLS_IE_LO12_S,
+ BFD_RELOC_RISCV_TLS_GD_HI20,
+ BFD_RELOC_RISCV_TLS_GD_LO12,
+ BFD_RELOC_RISCV_TLS_PCREL_LO12,
+
/* 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 --git a/binutils-2.21.1/bfd/config.bfd b/binutils-2.21.1/bfd/config.bfd
index fbf77ad..5c5535e 100644
--- a/binutils-2.21.1/bfd/config.bfd
+++ binutils-2.21.1/bfd/config.bfd
@@ -96,6 +96,7 @@ or32*) targ_archs=bfd_or32_arch ;;
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 @@ case "${targ}" in
targ_selvecs="bfd_powerpcle_pei_vec bfd_powerpc_pei_vec bfd_powerpcle_pe_vec bfd_powerpc_pe_vec"
;;
+#ifdef BFD64
+ riscv*-*-*)
+ 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 --git a/binutils-2.21.1/bfd/configure b/binutils-2.21.1/bfd/configure
index 4675ad2..e882968 100755
--- a/binutils-2.21.1/bfd/configure
+++ binutils-2.21.1/bfd/configure
@@ -15239,6 +15239,7 @@ do
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 @@ do
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 --git a/binutils-2.21.1/bfd/configure.in b/binutils-2.21.1/bfd/configure.in
index 9f6d7a9..617b5df 100644
--- a/binutils-2.21.1/bfd/configure.in
+++ binutils-2.21.1/bfd/configure.in
@@ -730,6 +730,7 @@ do
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 @@ do
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 --git a/binutils-2.21.1/bfd/cpu-riscv.c b/binutils-2.21.1/bfd/cpu-riscv.c
new file mode 100644
index 0000000..0dbb3aa
--- /dev/null
+++ binutils-2.21.1/bfd/cpu-riscv.c
@@ -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_riscv64,
+ I_riscv32
+};
+
+#define NN(index) (&arch_info_struct[(index) + 1])
+
+static const bfd_arch_info_type arch_info_struct[] =
+{
+ N (64, 64, bfd_mach_riscv64, "riscv:rv64", FALSE, NN(I_riscv64)),
+ N (32, 32, bfd_mach_riscv32, "riscv:rv32", FALSE, 0)
+};
+
+/* The default architecture is riscv:rv64. */
+
+const bfd_arch_info_type bfd_riscv_arch =
+N (64, 64, 0, "riscv", TRUE, &arch_info_struct[0]);
diff --git a/binutils-2.21.1/bfd/doc/bfd.texinfo b/binutils-2.21.1/bfd/doc/bfd.texinfo
index 45ffa73..c3ca5e7 100644
--- a/binutils-2.21.1/bfd/doc/bfd.texinfo
+++ binutils-2.21.1/bfd/doc/bfd.texinfo
@@ -322,7 +322,7 @@ All of BFD lives in one directory.
@printindex cp
@tex
-% I think something like @colophon should be in texinfo. In the
+% I think something like @@colophon should be in texinfo. In the
% meantime:
\long\def\colophon{\hbox to0pt{}\vfill
\centerline{The body of this manual is set in}
@@ -333,7 +333,7 @@ All of BFD lives in one directory.
\centerline{{\sl\fontname\tensl\/}}
\centerline{are used for emphasis.}\vfill}
\page\colophon
-% Blame: doc@cygnus.com, 28mar91.
+% Blame: doc@@cygnus.com, 28mar91.
@end tex
@bye
diff --git a/binutils-2.21.1/bfd/elf32-riscv.c b/binutils-2.21.1/bfd/elf32-riscv.c
new file mode 100644
index 0000000..3ef28fa
--- /dev/null
+++ binutils-2.21.1/bfd/elf32-riscv.c
@@ -0,0 +1,225 @@
+/* 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"
+
+#include "opcode/riscv.h"
+
+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;
+
+/* The number of local .got entries we reserve. */
+#define MIPS_RESERVED_GOTNO (2)
+
+/* 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)));
+}
+
+/* Set the right machine number for a MIPS ELF file. */
+
+static bfd_boolean
+mips_elf_n32_object_p (bfd *abfd)
+{
+ bfd_default_set_arch_mach (abfd, bfd_arch_riscv, bfd_mach_riscv32);
+ return TRUE;
+}
+
+/* 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;
+}
+
+#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 riscv_elf_info_to_howto_rela
+#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_add_symbol_hook _bfd_riscv_elf_add_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_additional_program_headers \
+ _bfd_riscv_elf_additional_program_headers
+#define elf_backend_modify_segment_map _bfd_riscv_elf_modify_segment_map
+#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_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 bfd_elf32_new_section_hook _bfd_riscv_elf_new_section_hook
+#define bfd_elf32_bfd_get_relocated_section_contents \
+ bfd_generic_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_print_private_bfd_data \
+ _bfd_riscv_elf_print_private_bfd_data
+#define bfd_elf32_bfd_relax_section _bfd_riscv_relax_section
+#define bfd_elf32_bfd_reloc_type_lookup \
+ riscv_elf_bfd_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup \
+ riscv_elf_bfd_reloc_name_lookup
+
+/* 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 0x1000
+#define ELF_COMMONPAGESIZE 0x1000
+
+#include "elf32-target.h"
diff --git a/binutils-2.21.1/bfd/elf64-riscv.c b/binutils-2.21.1/bfd/elf64-riscv.c
new file mode 100644
index 0000000..d693841
--- /dev/null
+++ binutils-2.21.1/bfd/elf64-riscv.c
@@ -0,0 +1,245 @@
+/* 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"
+
+#include "opcode/riscv.h"
+
+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 *);
+
+/* The number of local .got entries we reserve. */
+#define MIPS_RESERVED_GOTNO (2)
+
+/* Set the right machine number for a MIPS ELF file. */
+
+static bfd_boolean
+mips_elf64_object_p (bfd *abfd)
+{
+ bfd_default_set_arch_mach (abfd, bfd_arch_riscv, bfd_mach_riscv64);
+ 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;
+}
+
+#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 riscv_elf_info_to_howto_rela
+#define elf_backend_object_p mips_elf64_object_p
+#define elf_backend_symbol_processing _bfd_riscv_elf_symbol_processing
+#define elf_backend_add_symbol_hook _bfd_riscv_elf_add_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_additional_program_headers \
+ _bfd_riscv_elf_additional_program_headers
+#define elf_backend_modify_segment_map _bfd_riscv_elf_modify_segment_map
+#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_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_new_section_hook _bfd_riscv_elf_new_section_hook
+#define bfd_elf64_bfd_get_relocated_section_contents \
+ bfd_generic_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_print_private_bfd_data \
+ _bfd_riscv_elf_print_private_bfd_data
+
+#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
+#define bfd_elf64_bfd_reloc_type_lookup \
+ riscv_elf_bfd_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+ riscv_elf_bfd_reloc_name_lookup
+/* 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 0x2000
+#define ELF_COMMONPAGESIZE 0x2000
+
+#include "elf64-target.h"
diff --git a/binutils-2.21.1/bfd/elfxx-riscv.c b/binutils-2.21.1/bfd/elfxx-riscv.c
new file mode 100644
index 0000000..08272f4
--- /dev/null
+++ binutils-2.21.1/bfd/elfxx-riscv.c
@@ -0,0 +1,5575 @@
+/* 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"
+
+#include "hashtab.h"
+#include <stdint.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). */
+ 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 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 number of local .got entries we have used. */
+ unsigned int assigned_gotno;
+ /* A hash table holding members of the got. */
+ struct htab *got_entries;
+};
+
+/* 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.
+
+ 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
+
+/* 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;
+
+ /* 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_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 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;
+};
+
+/* MIPS ELF linker hash table. */
+
+struct mips_elf_link_hash_table
+{
+ struct elf_link_hash_table root;
+
+ /* 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 *sgot;
+
+ /* The master GOT information. */
+ struct mips_got_info *got_info;
+
+ /* The number of PLT entries. */
+ bfd_vma nplt;
+
+ /* The number of reserved entries at the beginning of the GOT. */
+ unsigned int reserved_gotno;
+
+ /* Whether or not relaxation is enabled. */
+ bfd_boolean relax;
+};
+
+/* 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 \
+ || (r_type) == R_RISCV_TLS_TPREL32 \
+ || (r_type) == R_RISCV_TLS_TPREL64 \
+ || (r_type) == R_RISCV_TPREL_HI20 \
+ || (r_type) == R_RISCV_TPREL_LO12_I \
+ || (r_type) == R_RISCV_TPREL_LO12_S \
+ || (r_type) == R_RISCV_TPREL_ADD \
+ || TLS_GD_RELOC_P(r_type) \
+ || TLS_GOTTPREL_RELOC_P(r_type))
+
+#define TLS_GOTTPREL_RELOC_P(r_type) \
+ ((r_type) == R_RISCV_TLS_IE_HI20 \
+ || (r_type) == R_RISCV_TLS_IE_LO12 \
+ || (r_type) == R_RISCV_TLS_IE_ADD \
+ || (r_type) == R_RISCV_TLS_IE_LO12_I \
+ || (r_type) == R_RISCV_TLS_IE_LO12_S \
+ || (r_type) == R_RISCV_TLS_GOT_HI20 \
+ || (r_type) == R_RISCV_TLS_GOT_LO12)
+
+#define TLS_GD_RELOC_P(r_type) \
+ ((r_type) == R_RISCV_TLS_GD_HI20 \
+ || (r_type) == R_RISCV_TLS_GD_LO12)
+
+/* 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)
+
+
+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 *);
+
+/* This will be used when we sort the dynamic relocation records. */
+static bfd *reldyn_sorting_bfd;
+
+/* 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))
+
+/* 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 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))
+
+/* 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)
+
+#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) ? "/lib/ld.so.1" \
+ : "/lib32/ld.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)
+#define MATCH_SREG(abfd) (ABI_64_P(abfd) ? MATCH_SD : MATCH_SW)
+
+#define OPCODE_MATCHES(OPCODE, OP) \
+ (((OPCODE) & MASK_##OP) == MATCH_##OP)
+
+#define MINUS_ONE (((bfd_vma)0) - 1)
+
+/* The relocation table used for SHT_RELA sections. */
+
+static reloc_howto_type howto_table[] =
+{
+ /* 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_JAL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* 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_JAL", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UJTYPE_IMM(-1U), /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* High 16 bits of symbol value. */
+ HOWTO (R_RISCV_HI20, /* 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_HI20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 12 bits of symbol value. */
+ HOWTO (R_RISCV_LO12_I, /* 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_LO12_I", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U) | (OP_MASK_RS1 << OP_SH_RS1), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 12 bits of symbol value. */
+ HOWTO (R_RISCV_LO12_S, /* 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_LO12_S", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_STYPE_IMM(-1U) | (OP_MASK_RS1 << OP_SH_RS1), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Distance between AUIPC and corresponding ADD/load. */
+ HOWTO (R_RISCV_PCREL_LO12_I, /* 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_PCREL_LO12_I",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Distance between AUIPC and corresponding store. */
+ HOWTO (R_RISCV_PCREL_LO12_S, /* 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_PCREL_LO12_S",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_STYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_RISCV_BRANCH, /* type */
+ 0, /* 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_BRANCH", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_SBTYPE_IMM(-1U), /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_RISCV_CALL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_CALL", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_RISCV_PCREL_HI20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_PCREL_HI20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (R_RISCV_CALL_PLT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_CALL_PLT", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ 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 */
+
+ EMPTY_HOWTO (19),
+ EMPTY_HOWTO (20),
+ EMPTY_HOWTO (21),
+
+ /* High 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_GOT_HI20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_GOT_HI20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_GOT_LO12, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ RISCV_IMM_BITS, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_GOT_LO12", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ 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 */
+
+ 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 */
+
+ EMPTY_HOWTO (26),
+ EMPTY_HOWTO (27),
+ EMPTY_HOWTO (28),
+
+ /* TLS IE GOT access in non-PIC code. */
+ HOWTO (R_RISCV_TLS_IE_HI20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_TLS_IE_HI20", /* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE GOT access in non-PIC code. */
+ HOWTO (R_RISCV_TLS_IE_LO12, /* 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_IE_LO12_I",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE thread pointer usage. */
+ HOWTO (R_RISCV_TLS_IE_ADD, /* 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_IE_ADD", /* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE low-part relocation for relaxation. */
+ HOWTO (R_RISCV_TLS_IE_LO12_I, /* 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_IE_LO12_I",/* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE low-part relocation for relaxation. */
+ HOWTO (R_RISCV_TLS_IE_LO12_S, /* 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_IE_LO12_S",/* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS LE thread pointer offset. */
+ HOWTO (R_RISCV_TPREL_HI20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_TPREL_HI20", /* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS LE thread pointer offset. */
+ HOWTO (R_RISCV_TPREL_LO12_I, /* 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_TPREL_LO12_I",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U) | (OP_MASK_RS1 << OP_SH_RS1), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS LE thread pointer offset. */
+ HOWTO (R_RISCV_TPREL_LO12_S, /* 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_TPREL_LO12_S",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_STYPE_IMM(-1U) | (OP_MASK_RS1 << OP_SH_RS1), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS LE thread pointer usage. */
+ HOWTO (R_RISCV_TPREL_ADD, /* 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_TPREL_ADD", /* name */
+ TRUE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS relocations. */
+ HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
+ 0, /* rightshift */
+ 4, /* 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 */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_RISCV_TLS_DTPREL32, /* type */
+ 0, /* rightshift */
+ 4, /* 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 */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ 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 */
+
+ EMPTY_HOWTO (42),
+ EMPTY_HOWTO (43),
+ EMPTY_HOWTO (44),
+ EMPTY_HOWTO (45),
+ EMPTY_HOWTO (46),
+
+ 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 */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ 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 */
+
+ EMPTY_HOWTO (49),
+
+ /* Distance between AUIPC and corresponding ADD/load. */
+ HOWTO (R_RISCV_TLS_PCREL_LO12,/* 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_TLS_PCREL_LO12",/* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* High 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_TLS_GOT_HI20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_TLS_GOT_HI20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_TLS_GOT_LO12, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ RISCV_IMM_BITS, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_riscv_elf_generic_reloc, /* special_function */
+ "R_RISCV_TLS_GOT_LO12", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* High 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_TLS_GD_HI20, /* 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_GD_HI20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_UTYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ HOWTO (R_RISCV_TLS_GD_LO12, /* 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_TLS_GD_LO12", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_ITYPE_IMM(-1U), /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (55),
+ EMPTY_HOWTO (56),
+
+ /* 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 */
+
+ /* 32 bit in-place addition, for local label subtraction. */
+ HOWTO (R_RISCV_ADD32, /* 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_ADD32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 64 bit in-place addition, for local label subtraction. */
+ HOWTO (R_RISCV_ADD64, /* 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_ADD64", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 32 bit in-place addition, for local label subtraction. */
+ HOWTO (R_RISCV_SUB32, /* 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_SUB32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 64 bit in-place addition, for local label subtraction. */
+ HOWTO (R_RISCV_SUB64, /* 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_SUB64", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+};
+
+/* 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 riscv_reloc_map[] =
+{
+ { BFD_RELOC_NONE, R_RISCV_NONE },
+ { BFD_RELOC_32, R_RISCV_32 },
+ { BFD_RELOC_64, R_RISCV_64 },
+ { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
+ { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
+ { BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
+ { BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
+ { BFD_RELOC_CTOR, R_RISCV_64 },
+ { BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
+ { BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
+ { BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
+ { BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
+ { BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
+ { BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
+ { BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
+ { BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
+ { BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
+ { BFD_RELOC_MIPS_JMP, R_RISCV_JAL },
+ { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
+ { BFD_RELOC_RISCV_GOT_LO12, R_RISCV_GOT_LO12 },
+ { 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_TPREL32, R_RISCV_TLS_TPREL32 },
+ { BFD_RELOC_MIPS_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
+ { BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
+ { BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
+ { BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
+ { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
+ { BFD_RELOC_RISCV_TLS_IE_HI20, R_RISCV_TLS_IE_HI20 },
+ { BFD_RELOC_RISCV_TLS_IE_LO12, R_RISCV_TLS_IE_LO12 },
+ { BFD_RELOC_RISCV_TLS_IE_ADD, R_RISCV_TLS_IE_ADD },
+ { BFD_RELOC_RISCV_TLS_IE_LO12_S, R_RISCV_TLS_IE_LO12_S },
+ { BFD_RELOC_RISCV_TLS_IE_LO12_I, R_RISCV_TLS_IE_LO12_I },
+ { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
+ { BFD_RELOC_RISCV_TLS_GOT_LO12, R_RISCV_TLS_GOT_LO12 },
+ { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
+ { BFD_RELOC_RISCV_TLS_GD_LO12, R_RISCV_TLS_GD_LO12 },
+ { BFD_RELOC_RISCV_TLS_PCREL_LO12, R_RISCV_TLS_PCREL_LO12 },
+};
+
+/* Given a BFD reloc type, return a howto structure. */
+
+reloc_howto_type *
+riscv_elf_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ bfd_reloc_code_real_type code)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (riscv_reloc_map) / sizeof (riscv_reloc_map[0]); i++)
+ if (riscv_reloc_map[i].bfd_val == code)
+ return &howto_table[(int) riscv_reloc_map[i].elf_val];
+
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+}
+
+reloc_howto_type *
+riscv_elf_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++)
+ if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
+ return &howto_table[i];
+
+ return NULL;
+}
+
+/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */
+
+static reloc_howto_type *
+riscv_elf_rtype_to_howto (unsigned int r_type)
+{
+ BFD_ASSERT (r_type < (unsigned int) R_RISCV_max);
+ return &howto_table[r_type];
+}
+
+void
+riscv_elf_info_to_howto_rela (bfd *abfd, arelent *cache_ptr,
+ Elf_Internal_Rela *dst ATTRIBUTE_UNUSED)
+{
+ unsigned int r_type;
+
+ r_type = ELF_R_TYPE (abfd, dst->r_info);
+ cache_ptr->howto = riscv_elf_rtype_to_howto (r_type);
+ cache_ptr->addend = dst->r_addend;
+}
+
+#define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
+
+static bfd_vma
+riscv_elf_got_plt_val (bfd_vma plt_index, struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab = mips_elf_hash_table (info);
+ return sec_addr(htab->sgotplt)
+ + (2+plt_index) * MIPS_ELF_GOT_SIZE (elf_hash_table (info)->dynobj);
+}
+
+#define PLT_HEADER_INSNS 8
+#define PLT_ENTRY_INSNS 4
+#define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4)
+#define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4)
+
+#define X_V0 16
+#define X_V1 17
+#define X_T0 26
+#define X_T1 27
+#define X_T2 28
+
+/* The format of the first PLT entry. */
+
+static void
+riscv_make_plt0_entry(bfd* abfd, bfd_vma gotplt_addr, bfd_vma addr,
+ uint32_t entry[PLT_HEADER_INSNS])
+{
+ int regbytes = ABI_64_P(abfd) ? 8 : 4;
+
+ /* auipc t2, %hi(.got.plt)
+ sub v0, v0, v1 # shifted .got.plt offset + hdr size + 12
+ l[w|d] v1, %lo(.got.plt)(t2) # _dl_runtime_resolve
+ addi v0, v0, -(hdr size + 12) # shifted .got.plt offset
+ addi t0, t2, %lo(.got.plt) # &.got.plt
+ srli t1, v0, log2(16/PTRSIZE) # .got.plt offset
+ l[w|d] t0, PTRSIZE(t0) # link map
+ jr v1 */
+
+ entry[0] = RISCV_UTYPE(AUIPC, X_T2, RISCV_PCREL_HIGH_PART(gotplt_addr, addr));
+ entry[1] = RISCV_RTYPE(SUB, X_V0, X_V0, X_V1);
+ entry[2] = RISCV_ITYPE(LREG(abfd), X_V1, X_T2, RISCV_PCREL_LOW_PART(gotplt_addr, addr));
+ entry[3] = RISCV_ITYPE(ADDI, X_V0, X_V0, -(PLT_HEADER_SIZE + 12));
+ entry[4] = RISCV_ITYPE(ADDI, X_T0, X_T2, RISCV_PCREL_LOW_PART(gotplt_addr, addr));
+ entry[5] = RISCV_ITYPE(SRLI, X_T1, X_V0, regbytes == 4 ? 2 : 1);
+ entry[6] = RISCV_ITYPE(LREG(abfd), X_T0, X_T0, regbytes);
+ entry[7] = RISCV_ITYPE(JALR, 0, X_V1, 0);
+}
+
+/* The format of subsequent PLT entries. */
+
+static bfd_vma
+riscv_make_plt_entry(bfd* abfd, bfd_vma got_address, bfd_vma plt0_addr,
+ bfd_vma addr, uint32_t *entry)
+{
+ /* auipc v0, %hi(.got.plt entry)
+ l[w|d] v1, %lo(.got.plt entry)(v0)
+ jalr v0, v1
+ nop */
+
+ entry[0] = RISCV_UTYPE(AUIPC, X_V0, RISCV_PCREL_HIGH_PART(got_address, addr));
+ entry[1] = RISCV_ITYPE(LREG(abfd), X_V1, X_V0, RISCV_PCREL_LOW_PART(got_address, addr));
+ entry[2] = RISCV_ITYPE(JALR, X_V0, X_V1, 0);
+ entry[3] = RISCV_NOP;
+ return plt0_addr;
+}
+
+/* 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 0
+#define DTP_OFFSET 0x800
+
+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)
+ {
+ ret->possibly_dynamic_relocs = 0;
+ ret->tls_type = GOT_NORMAL;
+ ret->global_got_area = GGA_NONE;
+ ret->readonly_reloc = FALSE;
+ ret->has_static_relocs = 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);
+}
+
+/* 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 += sec_addr(symbol->section);
+
+ 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 -= sec_addr(input_section);
+ 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 *loc = (bfd_byte *) data + reloc_entry->address;
+ struct reloc_howto_struct howto = *reloc_entry->howto;
+
+ /* Add in the separate addend, if any. */
+ val += reloc_entry->addend;
+
+ /* Add VAL to the reloc field. */
+ status = _bfd_relocate_contents (&howto, abfd, val, loc);
+
+ if (status != bfd_reloc_ok)
+ return status;
+ }
+
+ if (relocatable)
+ reloc_entry->address += input_section->output_offset;
+
+ return bfd_reloc_ok;
+}
+
+/* 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;
+ Elf_Internal_Rela int_reloc2;
+
+ (*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.r_info) < ELF64_R_SYM (int_reloc2.r_info))
+ return -1;
+ if (ELF64_R_SYM (int_reloc1.r_info) > ELF64_R_SYM (int_reloc2.r_info))
+ return 1;
+
+ if (int_reloc1.r_offset < int_reloc2.r_offset)
+ return -1;
+ if (int_reloc1.r_offset > int_reloc2.r_offset)
+ return 1;
+ return 0;
+#else
+ abort ();
+#endif
+}
+
+/* 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->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;
+
+ 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);
+}
+
+/* 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)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ need_relocs = TRUE;
+
+ if (!need_relocs)
+ return FALSE;
+
+ if (tls_type & GOT_TLS_GD)
+ {
+ ret++;
+ if (indx != 0)
+ ret++;
+ }
+
+ if (tls_type & GOT_TLS_IE)
+ ret++;
+
+ return ret;
+}
+
+/* Count the number of TLS relocations required for the GOT entry in
+ ARG1, if it describes a local symbol. */
+
+static int
+mips_elf_count_local_tls_relocs (void **arg1, void *arg2)
+{
+ struct mips_got_entry *entry = * (struct mips_got_entry **) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ if (entry->abfd != NULL && entry->symndx != -1)
+ arg->needed += mips_tls_got_relocs (arg->info, entry->tls_type, NULL);
+
+ return 1;
+}
+
+/* Count the number of TLS GOT entries required for the global (or
+ forced-local) symbol in ARG1. */
+
+static int
+mips_elf_count_global_tls_entries (void *arg1, void *arg2)
+{
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ if (hm->tls_type & GOT_TLS_GD)
+ arg->needed += 2;
+ if (hm->tls_type & GOT_TLS_IE)
+ arg->needed += 1;
+
+ return 1;
+}
+
+/* Count the number of TLS relocations required for the global (or
+ forced-local) symbol in ARG1. */
+
+static int
+mips_elf_count_global_tls_relocs (void *arg1, void *arg2)
+{
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ arg->needed += mips_tls_got_relocs (arg->info, hm->tls_type, &hm->root);
+
+ return 1;
+}
+
+/* Output a simple dynamic relocation into SRELOC. */
+
+static void
+mips_elf_output_dynamic_relocation (bfd *output_bfd,
+ asection *sreloc,
+ unsigned long reloc_index,
+ unsigned long indx,
+ int r_type,
+ bfd_vma offset)
+{
+ Elf_Internal_Rela rel;
+
+ memset (&rel, 0, sizeof (rel));
+
+ rel.r_info = ELF_R_INFO (output_bfd, indx, r_type);
+ rel.r_offset = offset;
+
+ if (ABI_64_P (output_bfd))
+ bfd_elf64_swap_reloc_out
+ (output_bfd, &rel,
+ (sreloc->contents + reloc_index * sizeof (Elf64_External_Rel)));
+ else
+ bfd_elf32_swap_reloc_out
+ (output_bfd, &rel,
+ (sreloc->contents + reloc_index * sizeof (Elf32_External_Rel)));
+}
+
+/* Initialize a set of TLS GOT entries for one symbol. */
+
+static void
+mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
+ unsigned char *tls_type_p,
+ struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h,
+ bfd_vma value)
+{
+ struct mips_elf_link_hash_table *htab;
+ int indx;
+ asection *sreloc, *sgot;
+ bfd_vma offset, offset2;
+ bfd_boolean need_relocs = FALSE;
+
+ htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return;
+
+ sgot = htab->sgot;
+
+ indx = 0;
+ if (h != NULL)
+ {
+ bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root)
+ && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ indx = h->root.dynindx;
+ }
+
+ if (*tls_type_p & GOT_TLS_DONE)
+ return;
+
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ need_relocs = TRUE;
+
+ /* MINUS_ONE means the symbol is not defined in this object. It may not
+ be defined at all; assume that the value doesn't matter in that
+ case. Otherwise complain if we would use the value. */
+ BFD_ASSERT (value != MINUS_ONE || (indx != 0 && need_relocs)
+ || h->root.root.type == bfd_link_hash_undefweak);
+
+ /* Emit necessary relocations. */
+ sreloc = mips_elf_rel_dyn_section (info, FALSE);
+
+ /* General Dynamic. */
+ if (*tls_type_p & GOT_TLS_GD)
+ {
+ offset = got_offset;
+ offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
+
+ if (need_relocs)
+ {
+ mips_elf_output_dynamic_relocation
+ (abfd, sreloc, sreloc->reloc_count++, indx,
+ ABI_64_P (abfd) ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32,
+ sec_addr(sgot) + offset);
+
+ if (indx)
+ mips_elf_output_dynamic_relocation
+ (abfd, sreloc, sreloc->reloc_count++, indx,
+ ABI_64_P (abfd) ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32,
+ sec_addr(sgot) + offset2);
+ else
+ MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
+ sgot->contents + offset2);
+ }
+ else
+ {
+ MIPS_ELF_PUT_WORD (abfd, 1,
+ sgot->contents + offset);
+ MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
+ sgot->contents + offset2);
+ }
+
+ got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd);
+ }
+
+ /* Initial Exec model. */
+ if (*tls_type_p & GOT_TLS_IE)
+ {
+ offset = got_offset;
+
+ if (need_relocs)
+ {
+ if (indx == 0)
+ MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma,
+ sgot->contents + offset);
+ else
+ MIPS_ELF_PUT_WORD (abfd, 0,
+ sgot->contents + offset);
+
+ mips_elf_output_dynamic_relocation
+ (abfd, sreloc, sreloc->reloc_count++, indx,
+ ABI_64_P (abfd) ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32,
+ sec_addr(sgot) + offset);
+ }
+ else
+ MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info),
+ sgot->contents + offset);
+ }
+
+ *tls_type_p |= GOT_TLS_DONE;
+}
+
+/* Return the GOT index to use for a relocation of type R_TYPE against
+ a symbol accessed using TLS_TYPE models. The GOT entries for this
+ symbol in this GOT start at GOT_INDEX. This function initializes the
+ GOT entries and corresponding relocations. */
+
+static bfd_vma
+mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
+ int r_type, struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h, bfd_vma symbol)
+{
+ BFD_ASSERT (TLS_GOTTPREL_RELOC_P(r_type) || TLS_GD_RELOC_P(r_type));
+
+ mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
+
+ if (TLS_GOTTPREL_RELOC_P(r_type))
+ {
+ BFD_ASSERT (*tls_type & GOT_TLS_IE);
+ if (*tls_type & GOT_TLS_GD)
+ return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
+ else
+ return got_index;
+ }
+
+ BFD_ASSERT (*tls_type & GOT_TLS_GD);
+ return got_index;
+}
+
+/* Return the GOT offset for address VALUE. If there is not yet a GOT
+ entry for this value, create one. If R_SYMNDX refers to a TLS symbol,
+ create a TLS GOT entry instead. Return -1 if no satisfactory GOT
+ offset can be found. */
+
+static bfd_vma
+mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
+ bfd_vma value, unsigned long r_symndx,
+ struct mips_elf_link_hash_entry *h, int r_type)
+{
+ struct mips_elf_link_hash_table *htab;
+ struct mips_got_entry *entry;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value,
+ r_symndx, h, r_type);
+ if (!entry)
+ return MINUS_ONE;
+
+ if (TLS_RELOC_P (r_type))
+ {
+ if (entry->symndx == -1)
+ /* A type (3) entry in the single-GOT case. We use the symbol's
+ hash table entry to track the index. */
+ return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
+ r_type, info, h, value);
+ else
+ return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
+ r_type, info, h, value);
+ }
+ else
+ return entry->gotidx;
+}
+
+/* Returns the GOT index for the global symbol indicated by H. */
+
+static bfd_vma
+mips_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h,
+ int r_type, struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab;
+ bfd_vma got_index;
+ struct mips_got_info *g;
+ long global_got_dynindx = 0;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ g = htab->got_info;
+
+ if (g->global_gotsym != NULL)
+ global_got_dynindx = g->global_gotsym->dynindx;
+
+ if (TLS_RELOC_P (r_type))
+ {
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) h;
+ bfd_vma value = MINUS_ONE;
+
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section)
+ value = h->root.u.def.value + sec_addr(h->root.u.def.section);
+
+ got_index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type,
+ r_type, info, hm, value);
+ }
+ else
+ {
+ /* Once we determine the global GOT entry with the lowest dynamic
+ symbol table index, we must put all dynamic symbols with greater
+ indices into the GOT. That makes it easy to calculate the GOT
+ offset. */
+ BFD_ASSERT (h->dynindx >= global_got_dynindx);
+ got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
+ * MIPS_ELF_GOT_SIZE (abfd));
+ }
+ BFD_ASSERT (got_index < htab->sgot->size);
+
+ return got_index;
+}
+
+/* Create and return a local GOT entry for VALUE, which was calculated
+ from a symbol belonging to INPUT_SECTON. Return NULL if it could not
+ be created. If R_SYMNDX refers to a TLS symbol, create a TLS entry
+ instead. */
+
+static struct mips_got_entry *
+mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
+ bfd *ibfd, bfd_vma value,
+ unsigned long r_symndx,
+ struct mips_elf_link_hash_entry *h,
+ int r_type)
+{
+ struct mips_got_entry entry, **loc;
+ struct mips_got_info *g;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ entry.abfd = NULL;
+ entry.symndx = -1;
+ entry.d.address = value;
+ entry.tls_type = 0;
+
+ g = htab->got_info;
+
+ /* This function shouldn't be called for symbols that live in the global
+ area of the GOT. */
+ BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
+ if (TLS_RELOC_P (r_type))
+ {
+ struct mips_got_entry *p;
+
+ entry.abfd = ibfd;
+ if (h == NULL)
+ {
+ entry.symndx = r_symndx;
+ entry.d.addend = 0;
+ }
+ else
+ entry.d.h = h;
+
+ p = (struct mips_got_entry *)
+ htab_find (g->got_entries, &entry);
+
+ BFD_ASSERT (p);
+ return p;
+ }
+
+ loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
+ INSERT);
+ if (*loc)
+ return *loc;
+
+ entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+ entry.tls_type = 0;
+
+ *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+
+ if (! *loc)
+ return NULL;
+
+ memcpy (*loc, &entry, sizeof entry);
+
+ if (g->assigned_gotno > g->local_gotno)
+ {
+ (*loc)->gotidx = -1;
+ /* We didn't allocate enough space in the GOT. */
+ (*_bfd_error_handler)
+ (_("not enough GOT space for local GOT entries"));
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+
+ MIPS_ELF_PUT_WORD (abfd, value,
+ (htab->sgot->contents + entry.gotidx));
+
+ return *loc;
+}
+
+/* Return the number of dynamic section symbols required by OUTPUT_BFD.
+ The number might be exact or a worst-case estimate, depending on how
+ much information is available to elf_backend_omit_section_dynsym at
+ the current linking stage. */
+
+static bfd_size_type
+count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
+{
+ bfd_size_type count;
+
+ count = 0;
+ if (info->shared || elf_hash_table (info)->is_relocatable_executable)
+ {
+ asection *p;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (output_bfd);
+ for (p = output_bfd->sections; p ; p = p->next)
+ if ((p->flags & SEC_EXCLUDE) == 0
+ && (p->flags & SEC_ALLOC) != 0
+ && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
+ ++count;
+ }
+ return count;
+}
+
+/* Sort the dynamic symbol table so that symbols that need GOT entries
+ appear towards the end. */
+
+static bfd_boolean
+mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab;
+ struct mips_elf_hash_sort_data hsd;
+ struct mips_got_info *g;
+
+ if (elf_hash_table (info)->dynsymcount == 0)
+ return TRUE;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ g = htab->got_info;
+ if (g == NULL)
+ return TRUE;
+
+ hsd.low = NULL;
+ hsd.max_unref_got_dynindx
+ = hsd.min_got_dynindx
+ = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno);
+ hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
+ mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
+ elf_hash_table (info)),
+ mips_elf_sort_hash_table_f,
+ &hsd);
+
+ /* There should have been enough room in the symbol table to
+ accommodate both the GOT and non-GOT symbols. */
+ BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
+ BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx
+ == elf_hash_table (info)->dynsymcount);
+ BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
+ == g->global_gotno);
+
+ /* Now we know which dynamic symbol has the lowest dynamic symbol
+ table index in the GOT. */
+ g->global_gotsym = hsd.low;
+
+ return TRUE;
+}
+
+/* If H needs a GOT entry, assign it the highest available dynamic
+ index. Otherwise, assign it the lowest available dynamic
+ index. */
+
+static bfd_boolean
+mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
+{
+ struct mips_elf_hash_sort_data *hsd = data;
+
+ if (h->root.root.type == bfd_link_hash_warning)
+ h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ /* Symbols without dynamic symbol table entries aren't interesting
+ at all. */
+ if (h->root.dynindx == -1)
+ return TRUE;
+
+ switch (h->global_got_area)
+ {
+ case GGA_NONE:
+ h->root.dynindx = hsd->max_non_got_dynindx++;
+ break;
+
+ case GGA_NORMAL:
+ BFD_ASSERT (h->tls_type == GOT_NORMAL);
+
+ h->root.dynindx = --hsd->min_got_dynindx;
+ hsd->low = (struct elf_link_hash_entry *) h;
+ break;
+
+ case GGA_RELOC_ONLY:
+ BFD_ASSERT (h->tls_type == GOT_NORMAL);
+
+ if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
+ hsd->low = (struct elf_link_hash_entry *) h;
+ h->root.dynindx = hsd->max_unref_got_dynindx++;
+ break;
+ }
+
+ return TRUE;
+}
+
+/* If H is a symbol that needs a global GOT entry, but has a dynamic
+ symbol table index lower than any we've seen to date, record it for
+ posterity. FOR_CALL is true if the caller is only interested in
+ using the GOT entry for calls. */
+
+static bfd_boolean
+mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
+ bfd *abfd, struct bfd_link_info *info,
+ unsigned char tls_flag)
+{
+ struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_entry *hmips;
+ struct mips_got_entry entry, **loc;
+ struct mips_got_info *g;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ hmips = (struct mips_elf_link_hash_entry *) h;
+
+ /* A global symbol in the GOT must also be in the dynamic symbol
+ table. */
+ if (h->dynindx == -1)
+ {
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+ break;
+ }
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ /* Make sure we have a GOT to put this entry into. */
+ g = htab->got_info;
+ BFD_ASSERT (g != NULL);
+
+ entry.abfd = abfd;
+ entry.symndx = -1;
+ entry.d.h = (struct mips_elf_link_hash_entry *) h;
+ entry.tls_type = 0;
+
+ loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
+ INSERT);
+
+ /* If we've already marked this entry as needing GOT space, we don't
+ need to do it again. */
+ if (*loc)
+ {
+ (*loc)->tls_type |= tls_flag;
+ return TRUE;
+ }
+
+ *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+
+ if (! *loc)
+ return FALSE;
+
+ entry.gotidx = -1;
+ entry.tls_type = tls_flag;
+
+ memcpy (*loc, &entry, sizeof entry);
+
+ if (tls_flag == 0)
+ hmips->global_got_area = GGA_NORMAL;
+
+ return TRUE;
+}
+
+/* Reserve space in G for a GOT entry containing the value of symbol
+ SYMNDX in input bfd ABDF, plus ADDEND. */
+
+static bfd_boolean
+mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
+ struct bfd_link_info *info,
+ unsigned char tls_flag)
+{
+ struct mips_elf_link_hash_table *htab;
+ struct mips_got_info *g;
+ struct mips_got_entry entry, **loc;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ g = htab->got_info;
+ BFD_ASSERT (g != NULL);
+
+ entry.abfd = abfd;
+ entry.symndx = symndx;
+ entry.d.addend = addend;
+ entry.tls_type = tls_flag;
+ loc = (struct mips_got_entry **)
+ htab_find_slot (g->got_entries, &entry, INSERT);
+
+ if (*loc)
+ {
+ if (tls_flag == GOT_TLS_GD && !((*loc)->tls_type & GOT_TLS_GD))
+ {
+ g->tls_gotno += 2;
+ (*loc)->tls_type |= tls_flag;
+ }
+ else if (tls_flag == GOT_TLS_IE && !((*loc)->tls_type & GOT_TLS_IE))
+ {
+ g->tls_gotno += 1;
+ (*loc)->tls_type |= tls_flag;
+ }
+ return TRUE;
+ }
+
+ if (tls_flag != 0)
+ {
+ entry.gotidx = -1;
+ entry.tls_type = tls_flag;
+ BFD_ASSERT (tls_flag & (GOT_TLS_IE | GOT_TLS_GD));
+ if (tls_flag == GOT_TLS_IE)
+ g->tls_gotno += 1;
+ else
+ g->tls_gotno += 2;
+ }
+ else
+ {
+ entry.gotidx = g->local_gotno++;
+ entry.tls_type = 0;
+ }
+
+ *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
+
+ if (! *loc)
+ return FALSE;
+
+ memcpy (*loc, &entry, sizeof entry);
+
+ return TRUE;
+}
+
+/* Add room for N relocations to the .rel(a).dyn section in ABFD. */
+
+static void
+mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
+ unsigned int n)
+{
+ asection *s;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ s = mips_elf_rel_dyn_section (info, FALSE);
+ BFD_ASSERT (s != NULL);
+
+ if (s->size == 0)
+ {
+ /* Make room for a null element. */
+ s->size += MIPS_ELF_REL_SIZE (abfd);
+ ++s->reloc_count;
+ }
+ s->size += n * MIPS_ELF_REL_SIZE (abfd);
+}
+
+/* A htab_traverse callback for GOT entries. Set boolean *DATA to true
+ if the GOT entry is for an indirect or warning symbol. */
+
+static int
+mips_elf_check_recreate_got (void **entryp, void *data)
+{
+ struct mips_got_entry *entry;
+ bfd_boolean *must_recreate;
+
+ entry = (struct mips_got_entry *) *entryp;
+ must_recreate = (bfd_boolean *) data;
+ if (entry->abfd != NULL && entry->symndx == -1)
+ {
+ struct mips_elf_link_hash_entry *h;
+
+ h = entry->d.h;
+ if (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ {
+ *must_recreate = TRUE;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* A htab_traverse callback for GOT entries. Add all entries to
+ hash table *DATA, converting entries for indirect and warning
+ symbols into entries for the target symbol. Set *DATA to null
+ on error. */
+
+static int
+mips_elf_recreate_got (void **entryp, void *data)
+{
+ htab_t *new_got;
+ struct mips_got_entry *entry;
+ void **slot;
+
+ new_got = (htab_t *) data;
+ entry = (struct mips_got_entry *) *entryp;
+ if (entry->abfd != NULL && entry->symndx == -1)
+ {
+ struct mips_elf_link_hash_entry *h;
+
+ h = entry->d.h;
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ {
+ BFD_ASSERT (h->global_got_area == GGA_NONE);
+ h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+ }
+ entry->d.h = h;
+ }
+ slot = htab_find_slot (*new_got, entry, INSERT);
+ if (slot == NULL)
+ {
+ *new_got = NULL;
+ return 0;
+ }
+ if (*slot == NULL)
+ *slot = entry;
+ else
+ free (entry);
+ return 1;
+}
+
+/* If any entries in G->got_entries are for indirect or warning symbols,
+ replace them with entries for the target symbol. */
+
+static bfd_boolean
+mips_elf_resolve_final_got_entries (struct mips_got_info *g)
+{
+ bfd_boolean must_recreate;
+ htab_t new_got;
+
+ must_recreate = FALSE;
+ htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate);
+ if (must_recreate)
+ {
+ new_got = htab_create (htab_size (g->got_entries),
+ mips_elf_got_entry_hash,
+ mips_elf_got_entry_eq, NULL);
+ htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got);
+ if (new_got == NULL)
+ return FALSE;
+
+ /* Each entry in g->got_entries has either been copied to new_got
+ or freed. Now delete the hash table itself. */
+ htab_delete (g->got_entries);
+ g->got_entries = new_got;
+ }
+ return TRUE;
+}
+
+/* A mips_elf_link_hash_traverse callback for which DATA points
+ to the link_info structure. Count the number of type (3) entries
+ in the master GOT. */
+
+static int
+mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
+{
+ struct bfd_link_info *info;
+ struct mips_elf_link_hash_table *htab;
+ struct mips_got_info *g;
+
+ info = (struct bfd_link_info *) data;
+ htab = mips_elf_hash_table (info);
+ g = htab->got_info;
+ if (h->global_got_area != GGA_NONE)
+ {
+ /* Make a final decision about whether the symbol belongs in the
+ local or global GOT. Symbols that bind locally can (and in the
+ case of forced-local symbols, must) live in the local GOT.
+ Those that are aren't in the dynamic symbol table must also
+ live in the local GOT.
+
+ Note that the former condition does not always imply the
+ latter: symbols do not bind locally if they are completely
+ undefined. We'll report undefined symbols later if appropriate. */
+ if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root))
+ {
+ /* The symbol belongs in the local GOT. We no longer need this
+ entry if it was only used for relocations; those relocations
+ will be against the null or section symbol instead of H. */
+ if (h->global_got_area != GGA_RELOC_ONLY)
+ g->local_gotno++;
+ h->global_got_area = GGA_NONE;
+ }
+ else
+ {
+ g->global_gotno++;
+ if (h->global_got_area == GGA_RELOC_ONLY)
+ g->reloc_only_gotno++;
+ }
+ }
+ return 1;
+}
+
+/* Set the TLS GOT index for the GOT entry in ENTRYP. ENTRYP's NEXT field
+ is null iff there is just a single GOT. */
+
+static int
+mips_elf_initialize_tls_index (void **entryp, void *p)
+{
+ struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+ struct mips_got_info *g = p;
+ bfd_vma next_index;
+ unsigned char tls_type;
+
+ /* We're only interested in TLS symbols. */
+ if (entry->tls_type == 0)
+ return 1;
+
+ next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
+
+ if (entry->symndx == -1)
+ {
+ /* A type (3) got entry in the single-GOT case. We use the symbol's
+ hash table entry to track its index. */
+ if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+ return 1;
+ entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
+ entry->d.h->tls_got_offset = next_index;
+ tls_type = entry->d.h->tls_type;
+ }
+ else
+ {
+ entry->gotidx = next_index;
+ tls_type = entry->tls_type;
+ }
+
+ /* Account for the entries we've just allocated. */
+ if (tls_type & GOT_TLS_GD)
+ g->tls_assigned_gotno += 2;
+ if (tls_type & GOT_TLS_IE)
+ g->tls_assigned_gotno += 1;
+
+ return 1;
+}
+
+/* Return whether an input relocation is against a local symbol. */
+
+static bfd_boolean
+mips_elf_local_relocation_p (bfd *input_bfd,
+ const Elf_Internal_Rela *relocation,
+ asection **local_sections)
+{
+ unsigned long r_symndx;
+ Elf_Internal_Shdr *symtab_hdr;
+ size_t extsymoff;
+
+ r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
+
+ if (r_symndx < extsymoff)
+ return TRUE;
+ if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Create the .got section to hold the global offset table. */
+
+static bfd_boolean
+mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
+{
+ flagword flags;
+ register asection *s;
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+ struct mips_got_info *g;
+ bfd_size_type amt;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ /* This function may be called more than once. */
+ if (htab->sgot)
+ return TRUE;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+
+ /* We have to use an alignment of 2**4 here because this is hardcoded
+ in the function stub generation and in the linker script. */
+ s = bfd_make_section_with_flags (abfd, ".got", flags);
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, 4))
+ return FALSE;
+ htab->sgot = s;
+
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the
+ linker script because we don't want to define the symbol if we
+ are not creating a global offset table. */
+ bh = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
+ 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->non_elf = 0;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ elf_hash_table (info)->hgot = h;
+
+ if (info->shared
+ && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+
+ amt = sizeof (struct mips_got_info);
+ g = bfd_alloc (abfd, amt);
+ if (g == NULL)
+ return FALSE;
+ g->global_gotsym = NULL;
+ g->global_gotno = 0;
+ g->reloc_only_gotno = 0;
+ g->tls_gotno = 0;
+ g->local_gotno = 0;
+ g->assigned_gotno = 0;
+ g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
+ mips_elf_got_entry_eq, NULL);
+ if (g->got_entries == NULL)
+ return FALSE;
+ htab->got_info = g;
+ mips_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE;
+
+ /* We also need a .got.plt section when generating PLTs. */
+ s = bfd_make_section_with_flags (abfd, ".got.plt",
+ SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if (s == NULL)
+ return FALSE;
+ htab->sgotplt = s;
+
+ return TRUE;
+}
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+
+bfd_vma
+_bfd_riscv_elf_plt_sym_val (bfd_vma i, const asection *s,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ uint32_t plt0_1;
+ if (!bfd_get_section_contents (s->owner, (sec_ptr)s, &plt0_1, 4, 4))
+ return MINUS_ONE;
+ return s->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE;
+}
+
+/* Calculate the value produced by the RELOCATION (which comes from
+ the INPUT_BFD). The ADDEND is the addend to use for this
+ RELOCATION; RELOCATION->R_ADDEND is ignored.
+
+ The result of the relocation calculation is stored in VALUEP.
+ On exit, set *CROSS_MODE_JUMP_P to true if the relocation field
+ is a MIPS16 jump to non-MIPS16 code, or vice versa.
+
+ This function returns bfd_reloc_continue if the caller need take no
+ further action regarding this relocation, bfd_reloc_notsupported if
+ something goes dramatically wrong, bfd_reloc_overflow if an
+ overflow occurs, and bfd_reloc_ok to indicate success. */
+
+static bfd_reloc_status_type
+mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
+ asection *input_section,
+ struct bfd_link_info *info,
+ const Elf_Internal_Rela *relocation,
+ bfd_vma addend, reloc_howto_type *howto,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections, bfd_vma *valuep,
+ const char **namep, bfd_byte *contents)
+{
+ /* The eventual value we will return. */
+ bfd_vma value;
+ /* The address of the symbol against which the relocation is
+ occurring. */
+ bfd_vma symbol = 0;
+ /* The place (section offset or address) of the storage unit being
+ relocated. */
+ bfd_vma p;
+ /* The offset into the global offset table at which the address of
+ the relocation entry symbol, adjusted by the addend, resides
+ during execution. */
+ bfd_vma g = MINUS_ONE;
+ /* The section in which the symbol referenced by the relocation is
+ located. */
+ asection *sec = NULL;
+ struct mips_elf_link_hash_entry *h = NULL;
+ /* TRUE if the symbol referred to by this relocation is a local
+ symbol. */
+ bfd_boolean local_p;
+ Elf_Internal_Shdr *symtab_hdr;
+ size_t extsymoff;
+ unsigned long r_symndx;
+ int r_type;
+ /* TRUE if overflow occurred during the calculation of the
+ relocation value. */
+ bfd_boolean overflowed_p;
+ /* TRUE if this relocation refers to a MIPS16 function. */
+ struct mips_elf_link_hash_table *htab;
+ bfd *dynobj;
+ bfd_vma gp = _bfd_get_gp_value (abfd);
+
+ dynobj = elf_hash_table (info)->dynobj;
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ /* Parse the relocation. */
+ r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
+ r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+ p = sec_addr(input_section) + relocation->r_offset;
+
+ /* Assume that there will be no overflow. */
+ overflowed_p = FALSE;
+
+ /* Figure out whether or not the symbol is local, and get the offset
+ used in the array of hash table entries. */
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ local_p = mips_elf_local_relocation_p (input_bfd, relocation,
+ local_sections);
+ if (! elf_bad_symtab (input_bfd))
+ extsymoff = symtab_hdr->sh_info;
+ else
+ {
+ /* The symbol table does not follow the rule that local symbols
+ must come before globals. */
+ extsymoff = 0;
+ }
+
+ /* Figure out the value of the symbol. */
+ if (local_p)
+ {
+ Elf_Internal_Sym *sym;
+
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+
+ symbol = sec_addr(sec);
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
+ || (sec->flags & SEC_MERGE))
+ symbol += sym->st_value;
+ if ((sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
+ addend -= symbol;
+ addend += sec_addr(sec);
+ }
+
+ /* Record the name of this symbol, for our caller. */
+ *namep = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ if (*namep == '\0')
+ *namep = bfd_section_name (input_bfd, sec);
+ }
+ else
+ {
+ /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ? */
+
+ /* For global symbols we look up the symbol in the hash-table. */
+ h = ((struct mips_elf_link_hash_entry *)
+ elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
+ /* Find the real hash-table entry for this symbol. */
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ /* Record the name of this symbol, for our caller. */
+ *namep = h->root.root.root.string;
+
+ /* If this symbol is defined, calculate its address. */
+ if ((h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ && h->root.root.u.def.section)
+ {
+ sec = h->root.root.u.def.section;
+ if (sec->output_section)
+ symbol = h->root.root.u.def.value + sec_addr(sec);
+ else
+ symbol = h->root.root.u.def.value;
+ }
+ else if (h->root.root.type == bfd_link_hash_undefweak)
+ /* We allow relocations against undefined weak symbols, giving
+ it the value zero, so that you can undefined weak functions
+ and check to see if they exist by looking at their
+ addresses. */
+ symbol = 0;
+ else if (info->unresolved_syms_in_objects == RM_IGNORE
+ && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
+ symbol = 0;
+ else if (strcmp (*namep, "_DYNAMIC_LINKING") == 0)
+ {
+ /* If this is a dynamic link, we should have created a
+ _DYNAMIC_LINKING symbol
+ in in _bfd_riscv_elf_create_dynamic_sections.
+ Otherwise, we should define the symbol with a value of 0.
+ FIXME: It should probably get into the symbol table
+ somehow as well. */
+ BFD_ASSERT (! info->shared);
+ BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL);
+ symbol = 0;
+ }
+ else if ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.root.string, input_bfd,
+ input_section, relocation->r_offset,
+ (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
+ || ELF_ST_VISIBILITY (h->root.other)))
+ {
+ return bfd_reloc_undefined;
+ }
+ else
+ {
+ return bfd_reloc_notsupported;
+ }
+ }
+
+ local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
+
+ /* If we haven't already determined the GOT offset, and we're going
+ to need it, get it now. */
+ switch (r_type)
+ {
+ case R_RISCV_GOT_HI20:
+ case R_RISCV_GOT_LO12:
+ case R_RISCV_TLS_GD_HI20:
+ case R_RISCV_TLS_GD_LO12:
+ case R_RISCV_TLS_GOT_HI20:
+ case R_RISCV_TLS_GOT_LO12:
+ case R_RISCV_TLS_IE_HI20:
+ case R_RISCV_TLS_IE_LO12:
+ if (!local_p)
+ {
+ BFD_ASSERT (addend == 0);
+ g = mips_elf_global_got_index (dynobj, &h->root, r_type, info);
+ if (h->tls_type == GOT_NORMAL
+ && !elf_hash_table (info)->dynamic_sections_created)
+ /* This is a static link. We must initialize the GOT entry. */
+ MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
+ }
+ else
+ {
+ g = mips_elf_local_got_index (abfd, input_bfd, info,
+ symbol + addend, r_symndx, h, r_type);
+ if (g == MINUS_ONE)
+ return bfd_reloc_outofrange;
+ }
+
+ /* Convert GOT indices to actual offsets. */
+ g = sec_addr(mips_elf_hash_table (info)->sgot) + g;
+ break;
+ }
+
+ /* Figure out what kind of relocation is being performed. */
+ switch (r_type)
+ {
+ case R_RISCV_NONE:
+ return bfd_reloc_continue;
+
+ case R_RISCV_32:
+ case R_RISCV_REL32:
+ case R_RISCV_64:
+ if ((info->shared
+ || (htab->root.dynamic_sections_created
+ && h != NULL
+ && h->root.def_dynamic
+ && !h->root.def_regular
+ && !h->has_static_relocs))
+ && r_symndx != STN_UNDEF
+ && (h == NULL
+ || h->root.root.type != bfd_link_hash_undefweak
+ || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ /* If we're creating a shared library, then we can't know
+ where the symbol will end up. So, we create a relocation
+ record in the output, and leave the job up to the dynamic
+ linker. We must do the same for executable references to
+ shared library symbols, unless we've decided to use copy
+ relocs or PLTs instead. */
+ value = addend;
+ if (!mips_elf_create_dynamic_relocation (abfd,
+ info,
+ relocation,
+ h,
+ sec,
+ symbol,
+ &value,
+ input_section))
+ return bfd_reloc_undefined;
+ }
+ else
+ {
+ if (r_type != R_RISCV_REL32)
+ value = symbol + addend;
+ else
+ value = addend;
+ }
+ value &= howto->dst_mask;
+ break;
+
+ case R_RISCV_ADD32:
+ case R_RISCV_ADD64:
+ value = addend + symbol;
+ break;
+
+ case R_RISCV_SUB32:
+ case R_RISCV_SUB64:
+ value = bfd_get (howto->bitsize, input_bfd,
+ contents + relocation->r_offset);
+ value -= addend + symbol;
+ break;
+
+ case R_RISCV_CALL_PLT:
+ case R_RISCV_CALL:
+ {
+ bfd_vma auipc = bfd_get (32, input_bfd, contents + relocation->r_offset);
+ bfd_vma jalr = bfd_get (32, input_bfd, contents + relocation->r_offset + 4);
+
+ if (info->shared && h && h->root.plt.offset != MINUS_ONE)
+ symbol = sec_addr(htab->splt) + h->root.plt.offset;
+ value = addend + (symbol ? symbol : p);
+
+ auipc |= ENCODE_UTYPE_IMM (RISCV_PCREL_HIGH_PART (value, p));
+ jalr |= ENCODE_ITYPE_IMM (RISCV_PCREL_LOW_PART (value, p));
+
+ bfd_put (32, input_bfd, auipc, contents + relocation->r_offset);
+ bfd_put (32, input_bfd, jalr, contents + relocation->r_offset + 4);
+
+ return bfd_reloc_continue;
+ }
+ case R_RISCV_JAL:
+ if (info->shared && h && h->root.plt.offset != MINUS_ONE)
+ symbol = sec_addr(htab->splt) + h->root.plt.offset;
+ value = addend;
+ if (symbol)
+ value += symbol - p;
+ overflowed_p = !VALID_UJTYPE_IMM (value);
+ if (overflowed_p && !info->shared && VALID_ITYPE_IMM (value + p))
+ {
+ /* Not all is lost: we can instead use JALR rd, x0, address. */
+ bfd_vma jal = bfd_get (32, input_bfd, contents+relocation->r_offset);
+ jal = (jal & (OP_MASK_RD << OP_SH_RD)) | MATCH_JALR;
+ jal |= ENCODE_ITYPE_IMM (value + p);
+ bfd_put (32, input_bfd, jal, contents+relocation->r_offset);
+ return bfd_reloc_continue;
+ }
+ value = ENCODE_UJTYPE_IMM (value);
+ break;
+
+ case R_RISCV_BRANCH:
+ value = addend;
+ if (symbol)
+ value += symbol - p;
+ overflowed_p = !VALID_SBTYPE_IMM (value);
+ value = ENCODE_SBTYPE_IMM (value);
+ break;
+
+ case R_RISCV_TLS_DTPREL32:
+ case R_RISCV_TLS_DTPREL64:
+ value = ENCODE_ITYPE_IMM (addend + symbol - dtprel_base (info));
+ break;
+
+ case R_RISCV_TPREL_HI20:
+ value = RISCV_LUI_HIGH_PART (addend + symbol - tprel_base (info));
+ value = ENCODE_UTYPE_IMM (value);
+ break;
+
+ case R_RISCV_TPREL_ADD:
+ case R_RISCV_TLS_IE_ADD:
+ case R_RISCV_TLS_IE_LO12_I:
+ case R_RISCV_TLS_IE_LO12_S:
+ value = 0;
+ break;
+
+ case R_RISCV_TPREL_LO12_I:
+ case R_RISCV_TPREL_LO12_S:
+ {
+ bfd_vma insn = bfd_get (32, input_bfd, contents + relocation->r_offset);
+ bfd_vma rs1 = (insn >> OP_SH_RS1) & OP_MASK_RS1;
+
+ value = symbol + addend - tprel_base (info);
+ if (htab->relax && RISCV_CONST_HIGH_PART (value) == 0)
+ rs1 = TP_REG; /* Reference TP directly if possible. */
+
+ if (r_type == R_RISCV_TPREL_LO12_I)
+ value = ENCODE_ITYPE_IMM (value);
+ else
+ value = ENCODE_STYPE_IMM (value);
+ value |= rs1 << OP_SH_RS1;
+ break;
+ }
+
+ case R_RISCV_PCREL_HI20:
+ value = ENCODE_UTYPE_IMM (RISCV_PCREL_HIGH_PART (addend + symbol, p));
+ break;
+
+ case R_RISCV_TLS_IE_HI20:
+ value = ENCODE_UTYPE_IMM (RISCV_LUI_HIGH_PART (g));
+ break;
+
+ case R_RISCV_TLS_IE_LO12:
+ value = ENCODE_ITYPE_IMM (g);
+ break;
+
+ case R_RISCV_HI20:
+ value = ENCODE_UTYPE_IMM (RISCV_LUI_HIGH_PART (addend + symbol));
+ break;
+
+ case R_RISCV_TLS_PCREL_LO12:
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ {
+ bfd_vma insn = bfd_get (32, input_bfd, contents + relocation->r_offset);
+ bfd_vma rd = (insn >> OP_SH_RD) & OP_MASK_RD;
+ bfd_vma rs1 = (insn >> OP_SH_RS1) & OP_MASK_RS1;
+ value = -(p + addend);
+
+ if (r_type == R_RISCV_PCREL_LO12_S)
+ value = ENCODE_STYPE_IMM (EXTRACT_STYPE_IMM (insn) + value);
+ else if (rs1 == GP_REG && rd != GP_REG)
+ value = insn; /* This has been relaxed. Ignore it. */
+ else
+ value = ENCODE_ITYPE_IMM (EXTRACT_ITYPE_IMM (insn) + value);
+ break;
+ }
+
+ case R_RISCV_LO12_I:
+ case R_RISCV_LO12_S:
+ {
+ bfd_vma insn = bfd_get (32, input_bfd, contents + relocation->r_offset);
+ bfd_vma rs1 = (insn >> OP_SH_RS1) & OP_MASK_RS1;
+
+ value = symbol + addend;
+ if (htab->relax && gp != 0 && value != gp
+ && RISCV_CONST_HIGH_PART (value - gp) == 0)
+ {
+ /* Convert to GP-relative reference. */
+ value -= gp;
+ rs1 = GP_REG;
+ }
+
+ if (r_type == R_RISCV_LO12_I)
+ value = ENCODE_ITYPE_IMM (value);
+ else
+ value = ENCODE_STYPE_IMM (value);
+ value |= rs1 << OP_SH_RS1;
+ }
+ break;
+
+ case R_RISCV_TLS_GOT_HI20:
+ case R_RISCV_TLS_GD_HI20:
+ case R_RISCV_GOT_HI20:
+ value = ENCODE_UTYPE_IMM (RISCV_PCREL_HIGH_PART (g, p));
+ break;
+
+ case R_RISCV_TLS_GOT_LO12:
+ case R_RISCV_TLS_GD_LO12:
+ case R_RISCV_GOT_LO12:
+ value = ENCODE_ITYPE_IMM (g);
+ break;
+
+ default:
+ /* An unrecognized relocation type. */
+ return bfd_reloc_notsupported;
+ }
+
+ /* Store the VALUE for our caller. */
+ *valuep = value;
+ return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
+}
+
+/* Obtain the field relocated by RELOCATION. */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd *input_bfd, bfd_byte *contents)
+{
+ bfd_vma x;
+ bfd_byte *location = contents + relocation->r_offset;
+
+ /* Obtain the bytes. */
+ x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location);
+
+ return x;
+}
+
+/* It has been determined that the result of the RELOCATION is the
+ VALUE. Use HOWTO to place VALUE into the output file at the
+ appropriate position. The SECTION is the section to which the
+ relocation applies.
+ CROSS_MODE_JUMP_P is true if the relocation field
+ is a MIPS16 jump to non-MIPS16 code, or vice versa.
+
+ Returns FALSE if anything goes wrong. */
+
+static bfd_boolean
+mips_elf_perform_relocation (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd_vma value, bfd *input_bfd,
+ asection *input_section ATTRIBUTE_UNUSED, bfd_byte *contents)
+{
+ bfd_vma x;
+ bfd_byte *location;
+ bfd_vma dst_mask = howto->dst_mask;
+
+ /* Figure out where the relocation is occurring. */
+ location = contents + relocation->r_offset;
+
+ /* Obtain the current value. */
+ x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
+
+ /* Update the field. */
+ x = (x &~ dst_mask) | (value & dst_mask);
+
+ /* Put the value into the output. */
+ bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
+
+ return TRUE;
+}
+
+/* Create a rel.dyn relocation for the dynamic linker to resolve. REL
+ is the original relocation, which is now being transformed into a
+ dynamic relocation. The ADDENDP is adjusted if necessary; the
+ caller should store the result in place of the original addend. */
+
+static bfd_boolean
+mips_elf_create_dynamic_relocation (bfd *output_bfd,
+ struct bfd_link_info *info,
+ const Elf_Internal_Rela *rel,
+ struct mips_elf_link_hash_entry *h,
+ asection *sec, bfd_vma symbol,
+ bfd_vma *addendp, asection *input_section)
+{
+ Elf_Internal_Rela outrel;
+ asection *sreloc;
+ int r_type;
+ long indx;
+ bfd_boolean defined_p;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ r_type = ELF_R_TYPE (output_bfd, rel->r_info);
+ sreloc = mips_elf_rel_dyn_section (info, FALSE);
+ BFD_ASSERT (sreloc != NULL);
+ BFD_ASSERT (sreloc->contents != NULL);
+ BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd)
+ < sreloc->size);
+
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset);
+
+ if (outrel.r_offset == MINUS_ONE)
+ /* The relocation field has been deleted. */
+ return TRUE;
+
+ if (outrel.r_offset == MINUS_TWO)
+ {
+ /* The relocation field has been converted into a relative value of
+ some sort. Functions like _bfd_elf_write_section_eh_frame expect
+ the field to be fully relocated, so add in the symbol's value. */
+ *addendp += symbol;
+ return TRUE;
+ }
+
+ /* We must now calculate the dynamic symbol table index to use
+ in the relocation. */
+ if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
+ {
+ BFD_ASSERT (h->global_got_area != GGA_NONE);
+ indx = h->root.dynindx;
+ /* ??? glibc's ld.so just adds the final GOT entry to the
+ relocation field. It therefore treats relocs against
+ defined symbols in the same way as relocs against
+ undefined symbols. */
+ defined_p = FALSE;
+ }
+ else
+ {
+ if (sec != NULL && bfd_is_abs_section (sec))
+ indx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ indx = elf_section_data (sec->output_section)->dynindx;
+ if (indx == 0)
+ {
+ asection *osec = htab->root.text_index_section;
+ indx = elf_section_data (osec)->dynindx;
+ }
+ if (indx == 0)
+ abort ();
+ }
+
+ /* Instead of generating a relocation using the section
+ symbol, we may as well make it a fully relative
+ relocation. We want to avoid generating relocations to
+ local symbols because we used to generate them
+ incorrectly, without adding the original symbol value,
+ which is mandated by the ABI for section symbols. In
+ order to give dynamic loaders and applications time to
+ phase out the incorrect use, we refrain from emitting
+ section-relative relocations. It's not like they're
+ useful, after all. This should be a bit more efficient
+ as well. */
+ /* ??? Although this behavior is compatible with glibc's ld.so,
+ the ABI says that relocations against STN_UNDEF should have
+ a symbol value of 0. Irix rld honors this, so relocations
+ against STN_UNDEF have no effect. */
+ indx = 0;
+ defined_p = TRUE;
+ }
+
+ /* If the relocation was previously an absolute relocation and
+ this symbol will not be referred to by the relocation, we must
+ adjust it by the value we give it in the dynamic symbol table.
+ Otherwise leave the job up to the dynamic linker. */
+ if (defined_p && r_type != R_RISCV_REL32)
+ *addendp += symbol;
+
+ /* The relocation is always an REL32 relocation because we don't
+ know where the shared library will wind up at load-time. */
+ outrel.r_info = ELF_R_INFO (output_bfd, (unsigned long) indx,
+ R_RISCV_REL32);
+
+ /* Adjust the output offset of the relocation to reference the
+ correct location in the output file. */
+ outrel.r_offset += sec_addr(input_section);
+
+ /* Put the relocation back out. */
+ if (ABI_64_P (output_bfd))
+ bfd_elf64_swap_reloc_out
+ (output_bfd, &outrel,
+ (sreloc->contents + sreloc->reloc_count * sizeof (Elf64_External_Rel)));
+ else
+ bfd_elf32_swap_reloc_out
+ (output_bfd, &outrel,
+ (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+
+ /* We've now added another relocation. */
+ ++sreloc->reloc_count;
+
+ /* Make sure the output section is writable. The dynamic linker
+ will be writing to it. */
+ elf_section_data (input_section->output_section)->this_hdr.sh_flags
+ |= SHF_WRITE;
+
+ /* If we've written this relocation for a readonly section,
+ we need to set DF_TEXTREL again, so that we do not delete the
+ DT_TEXTREL tag. */
+ if (MIPS_ELF_READONLY_SECTION (input_section))
+ info->flags |= DF_TEXTREL;
+
+ return TRUE;
+}
+
+/* Return printable name for ABI. */
+
+static INLINE char *
+elf_mips_abi_name (bfd *abfd)
+{
+ return ABI_32_P (abfd) ? "rv32" : "rv64";
+}
+
+/* This is used for both the 32-bit and the 64-bit ABI. */
+
+void
+_bfd_riscv_elf_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym)
+{
+ elf_symbol_type *elfsym;
+
+ /* Handle the special MIPS section numbers that a symbol may use. */
+ elfsym = (elf_symbol_type *) asym;
+ switch (elfsym->internal_elf_sym.st_shndx)
+ {
+ case SHN_COMMON:
+ break;
+
+ case SHN_MIPS_SUNDEFINED:
+ asym->section = bfd_und_section_ptr;
+ break;
+ }
+
+ /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
+ if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
+ && (asym->value & 1) != 0)
+ {
+ asym->value--;
+ elfsym->internal_elf_sym.st_other
+ = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
+ }
+}
+
+/* Implement elf_backend_eh_frame_address_size. */
+
+unsigned int
+_bfd_riscv_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED)
+{
+ if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ return 8;
+ return 4;
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+ file. We must handle the special MIPS section numbers here. */
+
+bfd_boolean
+_bfd_riscv_elf_add_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *sym, const char **namep ATTRIBUTE_UNUSED,
+ flagword *flagsp ATTRIBUTE_UNUSED,
+ asection **secp, bfd_vma *valp ATTRIBUTE_UNUSED)
+{
+ switch (sym->st_shndx)
+ {
+ case SHN_COMMON:
+ break;
+
+ case SHN_MIPS_TEXT:
+ /* This section is used in a shared object. */
+ if (elf_tdata (abfd)->elf_text_section == NULL)
+ {
+ asymbol *elf_text_symbol;
+ asection *elf_text_section;
+ bfd_size_type amt = sizeof (asection);
+
+ elf_text_section = bfd_zalloc (abfd, amt);
+ if (elf_text_section == NULL)
+ return FALSE;
+
+ amt = sizeof (asymbol);
+ elf_text_symbol = bfd_zalloc (abfd, amt);
+ if (elf_text_symbol == NULL)
+ return FALSE;
+
+ /* Initialize the section. */
+
+ elf_tdata (abfd)->elf_text_section = elf_text_section;
+ elf_tdata (abfd)->elf_text_symbol = elf_text_symbol;
+
+ elf_text_section->symbol = elf_text_symbol;
+ elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol;
+
+ elf_text_section->name = ".text";
+ elf_text_section->flags = SEC_NO_FLAGS;
+ elf_text_section->output_section = NULL;
+ elf_text_section->owner = abfd;
+ elf_text_symbol->name = ".text";
+ elf_text_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC;
+ elf_text_symbol->section = elf_text_section;
+ }
+ /* This code used to do *secp = bfd_und_section_ptr if
+ info->shared. I don't know why, and that doesn't make sense,
+ so I took it out. */
+ *secp = elf_tdata (abfd)->elf_text_section;
+ break;
+
+ case SHN_MIPS_DATA:
+ /* This section is used in a shared object. */
+ if (elf_tdata (abfd)->elf_data_section == NULL)
+ {
+ asymbol *elf_data_symbol;
+ asection *elf_data_section;
+ bfd_size_type amt = sizeof (asection);
+
+ elf_data_section = bfd_zalloc (abfd, amt);
+ if (elf_data_section == NULL)
+ return FALSE;
+
+ amt = sizeof (asymbol);
+ elf_data_symbol = bfd_zalloc (abfd, amt);
+ if (elf_data_symbol == NULL)
+ return FALSE;
+
+ /* Initialize the section. */
+
+ elf_tdata (abfd)->elf_data_section = elf_data_section;
+ elf_tdata (abfd)->elf_data_symbol = elf_data_symbol;
+
+ elf_data_section->symbol = elf_data_symbol;
+ elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol;
+
+ elf_data_section->name = ".data";
+ elf_data_section->flags = SEC_NO_FLAGS;
+ elf_data_section->output_section = NULL;
+ elf_data_section->owner = abfd;
+ elf_data_symbol->name = ".data";
+ elf_data_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC;
+ elf_data_symbol->section = elf_data_section;
+ }
+ /* This code used to do *secp = bfd_und_section_ptr if
+ info->shared. I don't know why, and that doesn't make sense,
+ so I took it out. */
+ *secp = elf_tdata (abfd)->elf_data_section;
+ break;
+
+ case SHN_MIPS_SUNDEFINED:
+ *secp = bfd_und_section_ptr;
+ break;
+ }
+
+ return TRUE;
+}
+
+/* Functions for the dynamic linker. */
+
+/* Create dynamic sections when linking against a dynamic object. */
+
+bfd_boolean
+_bfd_riscv_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+{
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+ flagword flags;
+ register asection *s;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+
+ /* The psABI requires a read-only .dynamic section. */
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ if (! bfd_set_section_flags (abfd, s, flags))
+ return FALSE;
+ }
+
+ /* We need to create .got section. */
+ if (!mips_elf_create_got_section (abfd, info))
+ return FALSE;
+
+ if (! mips_elf_rel_dyn_section (info, TRUE))
+ return FALSE;
+
+ if (!info->shared)
+ {
+ const char *name;
+
+ name = "_DYNAMIC_LINKING";
+ bh = NULL;
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0,
+ NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->non_elf = 0;
+ h->def_regular = 1;
+ h->type = STT_SECTION;
+
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
+ Also create the _PROCEDURE_LINKAGE_TABLE symbol. */
+ if (!_bfd_elf_create_dynamic_sections (abfd, info))
+ return FALSE;
+
+ /* Cache the sections created above. */
+ htab->splt = bfd_get_section_by_name (abfd, ".plt");
+ htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
+ htab->srelplt = bfd_get_section_by_name (abfd, ".rel.plt");
+ if (!htab->sdynbss
+ || !htab->srelplt
+ || !htab->splt)
+ abort ();
+
+ return TRUE;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table. */
+
+bfd_boolean
+_bfd_riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
+ asection *sec, const Elf_Internal_Rela *relocs)
+{
+ const char *name;
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ size_t extsymoff;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sreloc;
+ const struct elf_backend_data *bed;
+
+ if (info->relocatable)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
+
+ bed = get_elf_backend_data (abfd);
+ rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+
+ name = bfd_get_section_name (abfd, sec);
+
+ sreloc = NULL;
+ for (rel = relocs; rel < rel_end; ++rel)
+ {
+ unsigned long r_symndx;
+ unsigned int r_type;
+ struct elf_link_hash_entry *h;
+ bfd_boolean can_make_dynamic_p;
+
+ r_symndx = ELF_R_SYM (abfd, rel->r_info);
+ r_type = ELF_R_TYPE (abfd, rel->r_info);
+
+ if (r_symndx < extsymoff)
+ h = NULL;
+ else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ (*_bfd_error_handler)
+ (_("%B: Malformed reloc detected for section %s"),
+ abfd, name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ h = sym_hashes[r_symndx - extsymoff];
+ while (h != NULL
+ && (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning))
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
+ relocation into a dynamic one. */
+ can_make_dynamic_p = FALSE;
+ switch (r_type)
+ {
+ case R_RISCV_GOT_HI20:
+ case R_RISCV_GOT_LO12:
+ case R_RISCV_TLS_GOT_HI20:
+ case R_RISCV_TLS_GOT_LO12:
+ case R_RISCV_TLS_GD_HI20:
+ case R_RISCV_TLS_GD_LO12:
+ case R_RISCV_TLS_IE_HI20:
+ case R_RISCV_TLS_IE_LO12:
+ case R_RISCV_TLS_IE_ADD:
+ case R_RISCV_TLS_IE_LO12_I:
+ case R_RISCV_TLS_IE_LO12_S:
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (!mips_elf_create_got_section (dynobj, info))
+ return FALSE;
+ break;
+
+ case R_RISCV_32:
+ case R_RISCV_REL32:
+ case R_RISCV_64:
+ /* For executables that use PLTs and copy-relocs, we have a
+ choice between converting the relocation into a dynamic
+ one or using copy relocations or PLT entries. It is
+ usually better to do the former, unless the relocation is
+ against a read-only section. */
+ if ((info->shared
+ || (h != NULL
+ && !(!info->nocopyreloc && MIPS_ELF_READONLY_SECTION (sec))))
+ && (sec->flags & SEC_ALLOC) != 0)
+ {
+ can_make_dynamic_p = TRUE;
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ break;
+ }
+ /* For sections that are not SEC_ALLOC a copy reloc would be
+ output if possible (implying questionable semantics for
+ read-only data objects) or otherwise the final link would
+ fail as ld.so will not process them and could not therefore
+ handle any outstanding dynamic relocations.
+
+ For such sections that are also SEC_DEBUGGING, we can avoid
+ these problems by simply ignoring any relocs as these
+ sections have a predefined use and we know it is safe to do
+ so.
+
+ This is needed in cases such as a global symbol definition
+ in a shared library causing a common symbol from an object
+ file to be converted to an undefined reference. If that
+ happens, then all the relocations against this symbol from
+ SEC_DEBUGGING sections in the object file will resolve to
+ nil. */
+ if ((sec->flags & SEC_DEBUGGING) != 0)
+ break;
+ /* Fall through. */
+
+ default:
+ /* Most static relocations require pointer equality, except
+ for branches. */
+ if (h)
+ h->pointer_equality_needed = TRUE;
+ /* Fall through. */
+
+ case R_RISCV_CALL_PLT:
+ if (info->shared && h)
+ h->needs_plt = TRUE;
+ case R_RISCV_JAL:
+ case R_RISCV_CALL:
+ if (h)
+ ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
+ case R_RISCV_BRANCH:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_RISCV_GOT_LO12:
+ if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
+ rel->r_addend, info, 0))
+ return FALSE;
+ /* Fall through. */
+ case R_RISCV_GOT_HI20:
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+ return FALSE;
+ break;
+
+ case R_RISCV_TLS_GOT_HI20:
+ case R_RISCV_TLS_GOT_LO12:
+ case R_RISCV_TLS_IE_HI20:
+ case R_RISCV_TLS_IE_LO12:
+ if (info->shared)
+ info->flags |= DF_STATIC_TLS;
+ /* Fall through */
+
+ case R_RISCV_TLS_GD_HI20:
+ case R_RISCV_TLS_GD_LO12:
+ /* This symbol requires a global offset table entry, or two
+ for TLS GD relocations. */
+ {
+ unsigned char flag = (TLS_GD_RELOC_P(r_type)
+ ? GOT_TLS_GD
+ : GOT_TLS_IE);
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *hmips =
+ (struct mips_elf_link_hash_entry *) h;
+ hmips->tls_type |= flag;
+
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info, flag))
+ return FALSE;
+ }
+ else
+ {
+ BFD_ASSERT (r_symndx != STN_UNDEF);
+
+ if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
+ rel->r_addend,
+ info, flag))
+ return FALSE;
+ }
+ }
+ break;
+
+ case R_RISCV_32:
+ case R_RISCV_REL32:
+ case R_RISCV_64:
+ /* In VxWorks executables, references to external symbols
+ are handled using copy relocs or PLT stubs, so there's
+ no need to add a .rela.dyn entry for this relocation. */
+ if (can_make_dynamic_p)
+ {
+ if (sreloc == NULL)
+ {
+ sreloc = mips_elf_rel_dyn_section (info, TRUE);
+ if (sreloc == NULL)
+ return FALSE;
+ }
+ if (info->shared && h == NULL)
+ {
+ /* When creating a shared object, we must copy these
+ reloc types into the output file as R_RISCV_REL32
+ relocs. Make room for this reloc in .rel(a).dyn. */
+ mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
+ if (MIPS_ELF_READONLY_SECTION (sec))
+ /* We tell the dynamic linker that there are
+ relocations against the text segment. */
+ info->flags |= DF_TEXTREL;
+ }
+ else
+ {
+ struct mips_elf_link_hash_entry *hmips;
+
+ /* For a shared object, we must copy this relocation
+ unless the symbol turns out to be undefined and
+ weak with non-default visibility, in which case
+ it will be left as zero.
+
+ We could elide R_RISCV_REL32 for locally binding symbols
+ in shared libraries, but do not yet do so.
+
+ For an executable, we only need to copy this
+ reloc if the symbol is defined in a dynamic
+ object. */
+ hmips = (struct mips_elf_link_hash_entry *) h;
+ ++hmips->possibly_dynamic_relocs;
+ if (MIPS_ELF_READONLY_SECTION (sec))
+ /* We need it to tell the dynamic linker if there
+ are relocations against the text segment. */
+ hmips->readonly_reloc = TRUE;
+ }
+ }
+
+ break;
+
+ case R_RISCV_JAL:
+ break;
+
+ case R_RISCV_HI20:
+ case R_RISCV_TPREL_HI20:
+ /* Can't use these in a shared library. */
+ if (info->shared)
+ {
+ reloc_howto_type *howto = riscv_elf_rtype_to_howto (r_type);
+ (*_bfd_error_handler)
+ (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
+ abfd, howto->name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Allocate space for global sym dynamic relocs. */
+
+static bfd_boolean
+allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+{
+ struct bfd_link_info *info = inf;
+ bfd *dynobj;
+ struct mips_elf_link_hash_entry *hmips;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ dynobj = elf_hash_table (info)->dynobj;
+ hmips = (struct mips_elf_link_hash_entry *) h;
+
+ /* Ignore indirect and warning symbols. All relocations against
+ such symbols will be redirected to the target symbol. */
+ if (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ return TRUE;
+
+ /* If this symbol is defined in a dynamic object, or we are creating
+ a shared library, we will need to copy any R_RISCV_32 or
+ R_RISCV_REL32 relocs against it into the output file. */
+ if (! info->relocatable
+ && hmips->possibly_dynamic_relocs != 0
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular
+ || info->shared))
+ {
+ bfd_boolean do_copy = TRUE;
+
+ if (h->root.type == bfd_link_hash_undefweak)
+ {
+ /* Do not copy relocations for undefined weak symbols with
+ non-default visibility. */
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ do_copy = FALSE;
+
+ /* Make sure undefined weak symbols are output as a dynamic
+ symbol in PIEs. */
+ else if (h->dynindx == -1 && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+ }
+
+ if (do_copy)
+ {
+ /* Even though we don't directly need a GOT entry for this symbol,
+ the SVR4 psABI requires it to have a dynamic symbol table
+ index greater that DT_RISCV_GOTSYM if there are dynamic
+ relocations against it. */
+ if (hmips->global_got_area > GGA_RELOC_ONLY)
+ hmips->global_got_area = GGA_RELOC_ONLY;
+
+ mips_elf_allocate_dynamic_relocations
+ (dynobj, info, hmips->possibly_dynamic_relocs);
+ if (hmips->readonly_reloc)
+ /* We tell the dynamic linker that there are relocations
+ against the text segment. */
+ info->flags |= DF_TEXTREL;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+bfd_boolean
+_bfd_riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ bfd *dynobj;
+ struct mips_elf_link_hash_entry *hmips;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ dynobj = elf_hash_table (info)->dynobj;
+ hmips = (struct mips_elf_link_hash_entry *) h;
+
+ /* Make sure we know what is going on here. */
+ BFD_ASSERT (dynobj != NULL
+ && (h->needs_plt
+ || h->u.weakdef != NULL
+ || (h->def_dynamic
+ && h->ref_regular
+ && !h->def_regular)));
+
+ hmips = (struct mips_elf_link_hash_entry *) h;
+
+ /* Establish PLT entries for functions that don't bind locally. */
+ if (h->type == STT_FUNC && hmips->has_static_relocs
+ && !SYMBOL_CALLS_LOCAL (info, h)
+ && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak))
+ {
+ /* We'll turn this into an actual address once we know the PLT size. */
+ h->plt.offset = htab->nplt++;
+
+ return TRUE;
+ }
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->u.weakdef != NULL)
+ {
+ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+ || h->u.weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->u.weakdef->root.u.def.section;
+ h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ return TRUE;
+ }
+
+ /* Otherwise, there is nothing further to do for symbols defined
+ in regular objects. */
+ if (h->def_regular)
+ return TRUE;
+
+ /* There's also nothing more to do if we'll convert all relocations
+ against this symbol into dynamic relocations. */
+ if (!hmips->has_static_relocs)
+ return TRUE;
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+ {
+ mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
+ h->needs_copy = 1;
+ }
+
+ /* All relocations against this symbol that could have been made
+ dynamic will now refer to the local copy instead. */
+ hmips->possibly_dynamic_relocs = 0;
+
+ return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
+}
+
+bfd_boolean
+_bfd_riscv_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+static struct bfd_link_hash_entry *
+bfd_riscv_gp_hash (struct bfd_link_info *info)
+{
+ if (info->shared)
+ return NULL;
+ return bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE);
+}
+
+static bfd_vma
+bfd_riscv_init_gp_value (bfd *abfd, struct bfd_link_info *info)
+{
+ struct bfd_link_hash_entry *h = bfd_riscv_gp_hash (info);
+
+ if (h != NULL && h->type == bfd_link_hash_defined)
+ elf_gp (abfd) = h->u.def.value + sec_addr(h->u.def.section);
+
+ return elf_gp (abfd);
+}
+
+/* After the PLT has been sized, compute PLT entry offsets. */
+
+static int
+riscv_elf_compute_plt_offset (void *arg1, void *arg2)
+{
+ struct elf_link_hash_entry *h = arg1;
+ struct mips_elf_link_hash_table *htab = arg2;
+
+ if (h->plt.offset != MINUS_ONE)
+ {
+ h->plt.offset = h->plt.offset * PLT_ENTRY_SIZE + PLT_HEADER_SIZE;
+
+ /* If the output file has no definition of the symbol, set the
+ symbol's value to the address of the stub. */
+ if (!h->def_regular)
+ {
+ h->root.u.def.section = htab->splt;
+ h->root.u.def.value = h->plt.offset;
+ }
+ }
+
+ return 1;
+}
+
+/* If the link uses a GOT, lay it out and work out its size. */
+
+static bfd_boolean
+mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *s;
+ struct mips_got_info *g;
+ bfd_size_type loadable_size = 0;
+ bfd *sub;
+ struct mips_elf_count_tls_arg count_tls_arg;
+ struct mips_elf_link_hash_table *htab;
+ struct mips_elf_count_tls_arg arg;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ s = htab->sgot;
+ if (s == NULL)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ g = htab->got_info;
+
+ /* Allocate room for the reserved entries. */
+ BFD_ASSERT (g->assigned_gotno == 0);
+ htab->reserved_gotno = 2;
+ g->local_gotno += htab->reserved_gotno;
+ g->assigned_gotno = htab->reserved_gotno;
+
+ /* Replace entries for indirect and warning symbols with entries for
+ the target symbol. */
+ if (!mips_elf_resolve_final_got_entries (g))
+ return FALSE;
+
+ /* Count the number of GOT symbols. */
+ mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
+
+ /* Calculate the total loadable size of the output. That
+ will give us the maximum number of GOT_PAGE entries
+ required. */
+ for (sub = info->input_bfds; sub; sub = sub->link_next)
+ {
+ asection *subsection;
+
+ for (subsection = sub->sections;
+ subsection;
+ subsection = subsection->next)
+ {
+ if ((subsection->flags & SEC_ALLOC) == 0)
+ continue;
+ loadable_size += ((subsection->size + 0xf)
+ &~ (bfd_size_type) 0xf);
+ }
+ }
+
+ s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+ s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+
+ /* We need to calculate tls_gotno for global symbols at this point
+ instead of building it up earlier, to avoid doublecounting
+ entries for one global symbol from multiple input files. */
+ count_tls_arg.info = info;
+ count_tls_arg.needed = 0;
+ elf_link_hash_traverse (elf_hash_table (info),
+ mips_elf_count_global_tls_entries,
+ &count_tls_arg);
+ g->tls_gotno += count_tls_arg.needed;
+ s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+
+ /* Set up TLS entries. */
+ g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
+ htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
+
+ /* Allocate room for the TLS relocations. */
+ arg.info = info;
+ arg.needed = 0;
+ htab_traverse (g->got_entries, mips_elf_count_local_tls_relocs, &arg);
+ elf_link_hash_traverse (elf_hash_table (info),
+ mips_elf_count_global_tls_relocs, &arg);
+ if (arg.needed)
+ mips_elf_allocate_dynamic_relocations (dynobj, info, arg.needed);
+
+ return TRUE;
+}
+
+/* Set the sizes of the dynamic sections. */
+
+bfd_boolean
+_bfd_riscv_elf_size_dynamic_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *s, *sreldyn;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* If we have a PLT, size it and create its symbol. */
+ if (htab->nplt != 0 && htab->root.hplt == NULL)
+ {
+ struct elf_link_hash_entry *h;
+
+ BFD_ASSERT (htab->splt->size == 0);
+ htab->splt->size = PLT_HEADER_SIZE + htab->nplt * PLT_ENTRY_SIZE;
+
+ /* The last and first two entries in .got.plt are reserved. */
+ BFD_ASSERT (htab->sgotplt->size == 0);
+ htab->sgotplt->size = (3 + htab->nplt) * MIPS_ELF_GOT_SIZE (dynobj);
+
+ /* Make room for the R_RISCV_JUMP_SLOT relocations. */
+ BFD_ASSERT (htab->srelplt->size == 0);
+ htab->srelplt->size = htab->nplt * MIPS_ELF_REL_SIZE (dynobj);
+
+ /* Adjust the PLT offsets. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ riscv_elf_compute_plt_offset,
+ htab);
+
+ /* PLT entries are 16 bytes. Don't let them span I$ lines. */
+ if (!bfd_set_section_alignment (dynobj, htab->splt, 4))
+ return FALSE;
+
+ /* The PLT header requires .got.plt be 2-word aligned. */
+ if (!bfd_set_section_alignment (dynobj, htab->sgotplt,
+ MIPS_ELF_LOG_FILE_ALIGN (dynobj)+1))
+ return FALSE;
+
+ /* Make the symbol. */
+ h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
+ "_PROCEDURE_LINKAGE_TABLE_");
+ htab->root.hplt = h;
+ if (h == NULL)
+ return FALSE;
+ h->type = STT_FUNC;
+ }
+
+ /* Set the contents of the .interp section to the interpreter. */
+ if (info->executable)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->size
+ = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
+ s->contents
+ = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
+ }
+ }
+
+ /* Allocate space for global sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
+
+ if (!mips_elf_lay_out_got (output_bfd, info))
+ return FALSE;
+
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ if (CONST_STRNEQ (name, ".rel"))
+ {
+ if (s->size != 0)
+ {
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ if (strcmp (name, MIPS_ELF_REL_DYN_NAME (info)) != 0)
+ s->reloc_count = 0;
+
+ /* If combreloc is enabled, elf_link_sort_relocs() will
+ sort relocations, but in a different way than we do,
+ and before we're done creating relocations. Also, it
+ will move them around between input sections'
+ relocation's contents, so our sorting would be
+ broken, so don't let it run. */
+ info->combreloc = 0;
+ }
+ }
+ else if (s == htab->splt)
+ {
+ }
+ else if (! CONST_STRNEQ (name, ".init")
+ && s != htab->sgot
+ && s != htab->sgotplt
+ && s != htab->sdynbss)
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (s->size == 0)
+ {
+ s->flags |= SEC_EXCLUDE;
+ continue;
+ }
+
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
+ /* Allocate memory for the section contents. */
+ s->contents = bfd_zalloc (dynobj, s->size);
+ if (s->contents == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return FALSE;
+ }
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in _bfd_riscv_elf_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. */
+
+ /* The DT_DEBUG entry may be filled in by the dynamic linker and
+ used by the debugger. */
+ if (info->executable
+ && !_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0))
+ return FALSE;
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (! _bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0))
+ return FALSE;
+
+ /* Clear the DF_TEXTREL flag. It will be set again if we
+ write out an actual text relocation; we may not, because
+ at this point we do not know whether e.g. any .eh_frame
+ absolute relocations have been converted to PC-relative. */
+ info->flags &= ~DF_TEXTREL;
+ }
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
+ return FALSE;
+
+ sreldyn = mips_elf_rel_dyn_section (info, FALSE);
+ {
+ if (sreldyn && sreldyn->size > 0)
+ {
+ if (! _bfd_elf_add_dynamic_entry (info, DT_REL, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RELSZ, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RELENT, 0))
+ return FALSE;
+ }
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RISCV_LOCAL_GOTNO, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RISCV_SYMTABNO, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RISCV_GOTSYM, 0))
+ return FALSE;
+ }
+ if (htab->splt->size > 0)
+ {
+ if (! _bfd_elf_add_dynamic_entry (info, DT_PLTREL, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0))
+ return FALSE;
+
+ if (! _bfd_elf_add_dynamic_entry (info, DT_RISCV_PLTGOT, 0))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* REL is a relocation in INPUT_BFD that is being copied to OUTPUT_BFD.
+ Adjust its R_ADDEND field so that it is correct for the output file.
+ LOCAL_SYMS and LOCAL_SECTIONS are arrays of INPUT_BFD's local symbols
+ and sections respectively; both use symbol indexes. */
+
+static void
+mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info,
+ bfd *input_bfd, Elf_Internal_Sym *local_syms,
+ asection **local_sections, Elf_Internal_Rela *rel)
+{
+ unsigned int r_symndx;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+ {
+ r_symndx = ELF_R_SYM (output_bfd, rel->r_info);
+ sym = local_syms + r_symndx;
+
+ /* Adjust REL's addend to account for section merging. */
+ if (!info->relocatable)
+ {
+ sec = local_sections[r_symndx];
+ _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+ }
+
+ /* This would normally be done by the rela_normal code in elflink.c. */
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += local_sections[r_symndx]->output_offset;
+ }
+}
+
+/* Relocate a MIPS ELF section. */
+
+bfd_boolean
+_bfd_riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, Elf_Internal_Rela *relocs,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections)
+{
+ Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *relend;
+ bfd_vma addend = 0;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (output_bfd);
+ relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
+ for (rel = relocs; rel < relend; ++rel)
+ {
+ const char *name;
+ bfd_vma value = 0;
+ /* TRUE if the relocation is a RELA relocation, rather than a
+ REL relocation. */
+ const char *msg;
+ unsigned long r_symndx;
+ asection *sec;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry *h;
+ unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info);
+ reloc_howto_type *howto = riscv_elf_rtype_to_howto (r_type);
+
+ r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
+ {
+ sec = local_sections[r_symndx];
+ h = NULL;
+ }
+ else
+ {
+ unsigned long extsymoff;
+
+ extsymoff = 0;
+ if (!elf_bad_symtab (input_bfd))
+ extsymoff = symtab_hdr->sh_info;
+ h = elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ sec = NULL;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ sec = h->root.u.def.section;
+ }
+
+ if (sec != NULL && elf_discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend, howto, contents);
+
+ addend = rel->r_addend;
+ mips_elf_adjust_addend (output_bfd, info, input_bfd,
+ local_syms, local_sections, rel);
+
+ if (info->relocatable)
+ /* Go on to the next relocation. */
+ continue;
+
+ /* Figure out what value we are supposed to relocate. */
+ switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
+ input_section, info, rel,
+ addend, howto, local_syms,
+ local_sections, &value, &name,
+ contents))
+ {
+ case bfd_reloc_continue:
+ /* There's nothing to do. */
+ continue;
+
+ case bfd_reloc_undefined:
+ /* mips_elf_calculate_relocation already called the
+ undefined_symbol callback. There's no real point in
+ trying to perform the relocation at this point, so we
+ just skip ahead to the next relocation. */
+ continue;
+
+ case bfd_reloc_notsupported:
+ msg = _("internal error: unsupported relocation error");
+ info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+
+ case bfd_reloc_overflow:
+ BFD_ASSERT (name != NULL);
+ if (! ((*info->callbacks->reloc_overflow)
+ (info, NULL, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset)))
+ return FALSE;
+ break;
+
+ case bfd_reloc_ok:
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ /* Actually perform the relocation. */
+ if (! mips_elf_perform_relocation (info, howto, rel, value,
+ input_bfd, input_section,
+ contents))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+bfd_boolean
+_bfd_riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ bfd *dynobj;
+ asection *sgot;
+ struct mips_got_info *g;
+ const char *name;
+ struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_entry *hmips;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+ dynobj = elf_hash_table (info)->dynobj;
+ hmips = (struct mips_elf_link_hash_entry *) h;
+
+ if (h->plt.offset != MINUS_ONE)
+ {
+ /* We've decided to create a PLT entry for this symbol. */
+ bfd_byte *loc;
+ bfd_vma i, header_address, plt_index, got_address, got_val;
+ uint32_t plt_entry[PLT_ENTRY_INSNS];
+
+ BFD_ASSERT (h->dynindx != -1);
+ BFD_ASSERT (htab->splt != NULL);
+ BFD_ASSERT (h->plt.offset <= htab->splt->size);
+
+ /* Calculate the address of the PLT header. */
+ header_address = sec_addr(htab->splt);
+
+ /* Calculate the index of the entry. */
+ plt_index = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+
+ /* Calculate the address of the .got.plt entry. */
+ got_address = riscv_elf_got_plt_val (plt_index, info);
+
+ /* Find out where the .plt entry should go. */
+ loc = htab->splt->contents + h->plt.offset;
+
+ /* Fill in the PLT entry itself. */
+ got_val = riscv_make_plt_entry (output_bfd, got_address, header_address,
+ header_address + h->plt.offset,
+ plt_entry);
+ for (i = 0; i < PLT_ENTRY_INSNS; i++)
+ bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
+
+ /* Fill in the initial value of the .got.plt entry. */
+ loc = htab->sgotplt->contents + (got_address - sec_addr(htab->sgotplt));
+ MIPS_ELF_PUT_WORD (output_bfd, got_val, loc);
+
+ /* Emit an R_RISCV_JUMP_SLOT relocation against the .got.plt entry. */
+ mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt,
+ plt_index, h->dynindx,
+ R_RISCV_JUMP_SLOT, got_address);
+
+ if (!h->def_regular)
+ sym->st_shndx = SHN_UNDEF;
+ }
+
+ BFD_ASSERT (h->dynindx != -1
+ || h->forced_local);
+
+ sgot = htab->sgot;
+ g = htab->got_info;
+ BFD_ASSERT (g != NULL);
+
+ /* Run through the global symbol table, creating GOT entries for all
+ the symbols that need them. */
+ if (hmips->global_got_area != GGA_NONE)
+ {
+ bfd_vma offset;
+ bfd_vma value;
+
+ value = sym->st_value;
+ offset = mips_elf_global_got_index (dynobj, h, R_RISCV_GOT_HI20, info);
+ MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
+ }
+
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
+ name = h->root.root.string;
+ if (strcmp (name, "_DYNAMIC") == 0
+ || h == elf_hash_table (info)->hgot)
+ sym->st_shndx = SHN_ABS;
+ else if (strcmp (name, "_DYNAMIC_LINKING") == 0)
+ {
+ sym->st_shndx = SHN_ABS;
+ sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ sym->st_value = 1;
+ }
+
+ /* Emit a copy reloc, if needed. */
+ if (h->needs_copy)
+ {
+ asection *s;
+ bfd_vma symval;
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ s = mips_elf_rel_dyn_section (info, FALSE);
+ symval = sec_addr(h->root.u.def.section) + h->root.u.def.value;
+ mips_elf_output_dynamic_relocation (output_bfd, s, s->reloc_count++,
+ h->dynindx, R_RISCV_COPY, symval);
+ }
+
+ return TRUE;
+}
+
+/* Write out a plt0 entry to the beginning of .plt. */
+
+static void
+mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
+{
+ bfd_byte *loc;
+ uint32_t plt_entry[PLT_HEADER_INSNS];
+ struct mips_elf_link_hash_table *htab;
+ int i;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ /* Install the PLT header. */
+ loc = htab->splt->contents;
+ riscv_make_plt0_entry (output_bfd, sec_addr(htab->sgotplt),
+ sec_addr(htab->splt), plt_entry);
+ for (i = 0; i < PLT_HEADER_INSNS; i++)
+ bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
+}
+
+/* Finish up the dynamic sections. */
+
+bfd_boolean
+_bfd_riscv_elf_finish_dynamic_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *sdyn;
+ asection *sgot;
+ struct mips_got_info *gg, *g;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+ sgot = htab->sgot;
+ g = gg = htab->got_info;
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ bfd_byte *b;
+ int dyn_to_skip = 0, dyn_skipped = 0;
+
+ BFD_ASSERT (sdyn != NULL);
+ BFD_ASSERT (gg != NULL);
+
+ for (b = sdyn->contents;
+ b < sdyn->contents + sdyn->size;
+ b += MIPS_ELF_DYN_SIZE (dynobj))
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ size_t elemsize;
+ asection *s;
+ bfd_boolean swap_out_p;
+
+ /* Read in the current dynamic entry. */
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
+
+ /* Assume that we're going to modify it and write it out. */
+ swap_out_p = TRUE;
+
+ switch (dyn.d_tag)
+ {
+ case DT_RELENT:
+ dyn.d_un.d_val = MIPS_ELF_REL_SIZE (dynobj);
+ break;
+
+ case DT_STRSZ:
+ /* Rewrite DT_STRSZ. */
+ dyn.d_un.d_val =
+ _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
+ break;
+
+ case DT_PLTGOT:
+ dyn.d_un.d_ptr = sec_addr(htab->sgot);
+ break;
+
+ case DT_RISCV_PLTGOT:
+ dyn.d_un.d_ptr = sec_addr(htab->sgotplt);
+ break;
+
+ case DT_RISCV_LOCAL_GOTNO:
+ dyn.d_un.d_val = g->local_gotno;
+ break;
+
+ case DT_RISCV_GOTSYM:
+ if (gg->global_gotsym)
+ {
+ dyn.d_un.d_val = gg->global_gotsym->dynindx;
+ break;
+ }
+ /* In case if we don't have global got symbols we default
+ to setting DT_RISCV_GOTSYM to the same value as
+ DT_RISCV_SYMTABNO, so we just fall through. */
+
+ case DT_RISCV_SYMTABNO:
+ name = ".dynsym";
+ elemsize = MIPS_ELF_SYM_SIZE (output_bfd);
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s != NULL);
+
+ dyn.d_un.d_val = s->size / elemsize;
+ break;
+
+ case DT_PLTREL:
+ dyn.d_un.d_val = DT_REL;
+ break;
+
+ case DT_PLTRELSZ:
+ dyn.d_un.d_val = htab->srelplt->size;
+ break;
+
+ case DT_JMPREL:
+ dyn.d_un.d_ptr = sec_addr(htab->srelplt);
+ break;
+
+ case DT_TEXTREL:
+ /* If we didn't need any text relocations after all, delete
+ the dynamic tag. */
+ if (!(info->flags & DF_TEXTREL))
+ {
+ dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+ swap_out_p = FALSE;
+ }
+ break;
+
+ case DT_FLAGS:
+ /* If we didn't need any text relocations after all, clear
+ DF_TEXTREL from DT_FLAGS. */
+ if (!(info->flags & DF_TEXTREL))
+ dyn.d_un.d_val &= ~DF_TEXTREL;
+ else
+ swap_out_p = FALSE;
+ break;
+
+ default:
+ swap_out_p = FALSE;
+ break;
+ }
+
+ if (swap_out_p || dyn_skipped)
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_out)
+ (dynobj, &dyn, b - dyn_skipped);
+
+ if (dyn_to_skip)
+ {
+ dyn_skipped += dyn_to_skip;
+ dyn_to_skip = 0;
+ }
+ }
+
+ /* Wipe out any trailing entries if we shifted down a dynamic tag. */
+ if (dyn_skipped > 0)
+ memset (b - dyn_skipped, 0, dyn_skipped);
+ }
+
+ if (sgot != NULL && sgot->size > 0
+ && !bfd_is_abs_section (sgot->output_section))
+ {
+ /* The first two entries of the GOT will be filled at runtime. */
+ MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents);
+ MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0,
+ sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd));
+
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize
+ = MIPS_ELF_GOT_SIZE (output_bfd);
+ }
+
+ /* The generation of dynamic relocations for the non-primary gots
+ adds more dynamic relocations. We cannot count them until
+ here. */
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ bfd_byte *b;
+ bfd_boolean swap_out_p;
+
+ BFD_ASSERT (sdyn != NULL);
+
+ for (b = sdyn->contents;
+ b < sdyn->contents + sdyn->size;
+ b += MIPS_ELF_DYN_SIZE (dynobj))
+ {
+ Elf_Internal_Dyn dyn;
+ asection *s;
+
+ /* Read in the current dynamic entry. */
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
+
+ /* Assume that we're going to modify it and write it out. */
+ swap_out_p = TRUE;
+
+ switch (dyn.d_tag)
+ {
+ case DT_RELSZ:
+ /* Reduce DT_RELSZ to account for any relocations we
+ decided not to make. This is for the n64 irix rld,
+ which doesn't seem to apply any relocations if there
+ are trailing null entries. */
+ s = mips_elf_rel_dyn_section (info, FALSE);
+ dyn.d_un.d_val = (s->reloc_count
+ * (ABI_64_P (output_bfd)
+ ? sizeof (Elf64_External_Rel)
+ : sizeof (Elf32_External_Rel)));
+ /* Adjust the section size too. Tools like the prelinker
+ can reasonably expect the values to the same. */
+ elf_section_data (s->output_section)->this_hdr.sh_size
+ = dyn.d_un.d_val;
+ break;
+
+ default:
+ swap_out_p = FALSE;
+ break;
+ }
+
+ if (swap_out_p)
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_out)
+ (dynobj, &dyn, b);
+ }
+ }
+
+ {
+ asection *s;
+
+ /* The psABI says that the dynamic relocations must be sorted in
+ increasing order of r_symndx. */
+ s = mips_elf_rel_dyn_section (info, FALSE);
+ if (s != NULL && s->size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd))
+ {
+ reldyn_sorting_bfd = output_bfd;
+
+ if (ABI_64_P (output_bfd))
+ qsort ((Elf64_External_Rel *) s->contents + 1,
+ s->reloc_count - 1, sizeof (Elf64_External_Rel),
+ sort_dynamic_relocs_64);
+ else
+ qsort ((Elf32_External_Rel *) s->contents + 1,
+ s->reloc_count - 1, sizeof (Elf32_External_Rel),
+ sort_dynamic_relocs);
+ }
+ }
+
+ if (htab->splt && htab->splt->size > 0)
+ mips_finish_exec_plt (output_bfd, info);
+ return TRUE;
+}
+
+int
+_bfd_riscv_elf_additional_program_headers (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ /* Allocate a PT_NULL header in dynamic objects. See
+ _bfd_riscv_elf_modify_segment_map for details. */
+ if (bfd_get_section_by_name (abfd, ".dynamic"))
+ return 1;
+ return 0;
+}
+
+/* Modify the segment map for an IRIX5 executable. */
+
+bfd_boolean
+_bfd_riscv_elf_modify_segment_map (bfd *abfd,
+ struct bfd_link_info *info)
+{
+ struct elf_segment_map *m, **pm;
+
+ {
+ /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic,
+ .dynstr, .dynsym, and .hash sections, and everything in
+ between. */
+ for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL;
+ pm = &(*pm)->next)
+ if ((*pm)->p_type == PT_DYNAMIC)
+ break;
+ m = *pm;
+ if (m != NULL)
+ {
+ /* For a normal mips executable the permissions for the PT_DYNAMIC
+ segment are read, write and execute. We do that here since
+ the code in elf.c sets only the read permission. This matters
+ sometimes for the dynamic linker. */
+ if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+ {
+ m->p_flags = PF_R | PF_W | PF_X;
+ m->p_flags_valid = 1;
+ }
+ }
+ }
+
+ /* Allocate a spare program header in dynamic objects so that tools
+ like the prelinker can add an extra PT_LOAD entry.
+
+ If the prelinker needs to make room for a new PT_LOAD entry, its
+ standard procedure is to move the first (read-only) sections into
+ the new (writable) segment. However, the MIPS ABI requires
+ .dynamic to be in a read-only segment, and the section will often
+ start within sizeof (ElfNN_Phdr) bytes of the last program header.
+
+ Although the prelinker could in principle move .dynamic to a
+ writable segment, it seems better to allocate a spare program
+ header instead, and avoid the need to move any sections.
+ There is a long tradition of allocating spare dynamic tags,
+ so allocating a spare program header seems like a natural
+ extension.
+
+ If INFO is NULL, we may be copying an already prelinked binary
+ with objcopy or strip, so do not add this header. */
+ if (info != NULL
+ && bfd_get_section_by_name (abfd, ".dynamic"))
+ {
+ for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next)
+ if ((*pm)->p_type == PT_NULL)
+ break;
+ if (*pm == NULL)
+ {
+ m = bfd_zalloc (abfd, sizeof (*m));
+ if (m == NULL)
+ return FALSE;
+
+ m->p_type = PT_NULL;
+ *pm = m;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Copy data from a MIPS ELF indirect symbol to its direct symbol,
+ hiding the old indirect symbol. Process additional relocation
+ information. Also called for weakdefs, in which case we just let
+ _bfd_elf_link_hash_copy_indirect copy the flags for us. */
+
+void
+_bfd_riscv_elf_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct mips_elf_link_hash_entry *dirmips, *indmips;
+
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+
+ dirmips = (struct mips_elf_link_hash_entry *) dir;
+ indmips = (struct mips_elf_link_hash_entry *) ind;
+ /* Any absolute non-dynamic relocations against an indirect or weak
+ definition will be against the target symbol. */
+ if (indmips->has_static_relocs)
+ dirmips->has_static_relocs = TRUE;
+
+ if (ind->root.type != bfd_link_hash_indirect)
+ return;
+
+ dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
+ if (indmips->readonly_reloc)
+ dirmips->readonly_reloc = TRUE;
+ if (indmips->global_got_area < dirmips->global_got_area)
+ dirmips->global_got_area = indmips->global_got_area;
+ if (indmips->global_got_area < GGA_NONE)
+ indmips->global_got_area = GGA_NONE;
+
+ if (dirmips->tls_type == 0)
+ dirmips->tls_type = indmips->tls_type;
+}
+
+#define PDR_SIZE 32
+
+bfd_boolean
+_bfd_riscv_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info)
+{
+ asection *o;
+ bfd_boolean ret = FALSE;
+ unsigned char *tdata;
+ size_t i, skip;
+
+ o = bfd_get_section_by_name (abfd, ".pdr");
+ if (! o)
+ return FALSE;
+ if (o->size == 0)
+ return FALSE;
+ if (o->size % PDR_SIZE != 0)
+ return FALSE;
+ if (o->output_section != NULL
+ && bfd_is_abs_section (o->output_section))
+ return FALSE;
+
+ tdata = bfd_zmalloc (o->size / PDR_SIZE);
+ if (! tdata)
+ return FALSE;
+
+ cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+ info->keep_memory);
+ if (!cookie->rels)
+ {
+ free (tdata);
+ return FALSE;
+ }
+
+ cookie->rel = cookie->rels;
+ cookie->relend = cookie->rels + o->reloc_count;
+
+ for (i = 0, skip = 0; i < o->size / PDR_SIZE; i ++)
+ {
+ if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
+ {
+ tdata[i] = 1;
+ skip ++;
+ }
+ }
+
+ if (skip != 0)
+ {
+ mips_elf_section_data (o)->u.tdata = tdata;
+ o->size -= skip * PDR_SIZE;
+ ret = TRUE;
+ }
+ else
+ free (tdata);
+
+ if (! info->keep_memory)
+ free (cookie->rels);
+
+ return ret;
+}
+
+bfd_boolean
+_bfd_riscv_elf_ignore_discarded_relocs (asection *sec)
+{
+ if (strcmp (sec->name, ".pdr") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+bfd_boolean
+_bfd_riscv_elf_write_section (bfd *output_bfd,
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
+ asection *sec, bfd_byte *contents)
+{
+ bfd_byte *to, *from, *end;
+ int i;
+
+ if (strcmp (sec->name, ".pdr") != 0)
+ return FALSE;
+
+ if (mips_elf_section_data (sec)->u.tdata == NULL)
+ return FALSE;
+
+ to = contents;
+ end = contents + sec->size;
+ for (from = contents, i = 0;
+ from < end;
+ from += PDR_SIZE, i++)
+ {
+ if ((mips_elf_section_data (sec)->u.tdata)[i] == 1)
+ continue;
+ if (to != from)
+ memcpy (to, from, PDR_SIZE);
+ to += PDR_SIZE;
+ }
+ bfd_set_section_contents (output_bfd, sec->output_section, contents,
+ sec->output_offset, sec->size);
+ return TRUE;
+}
+
+/* Create a MIPS ELF linker hash table. */
+
+struct bfd_link_hash_table *
+_bfd_riscv_elf_link_hash_table_create (bfd *abfd)
+{
+ struct mips_elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct mips_elf_link_hash_table);
+
+ ret = bfd_malloc (amt);
+ if (ret == NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+ mips_elf_link_hash_newfunc,
+ sizeof (struct mips_elf_link_hash_entry),
+ MIPS_ELF_DATA))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ ret->srelbss = NULL;
+ ret->sdynbss = NULL;
+ ret->srelplt = NULL;
+ ret->srelplt2 = NULL;
+ ret->sgotplt = NULL;
+ ret->splt = NULL;
+ ret->sgot = NULL;
+ ret->got_info = NULL;
+ ret->nplt = 0;
+
+ return &ret->root.root;
+}
+
+/* We need to use a special link routine to handle the .reginfo and
+ the .mdebug sections. We need to merge all instances of these
+ sections together, not write them all out sequentially. */
+
+bfd_boolean
+_bfd_riscv_elf_final_link (bfd *abfd, struct bfd_link_info *info)
+{
+ struct mips_elf_link_hash_table *htab;
+
+ bfd_riscv_init_gp_value (abfd, info);
+ /* Sort the dynamic symbols so that those with GOT entries come after
+ those without. */
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
+ if (!mips_elf_sort_hash_table (abfd, info))
+ return FALSE;
+
+ /* Invoke the regular ELF backend linker to do all the work. */
+ return bfd_elf_final_link (abfd, info);
+}
+
+/* Return true if bfd machine EXTENSION is an extension of machine BASE. */
+
+static bfd_boolean
+mips_mach_extends_p (unsigned long base, unsigned long extension)
+{
+ return extension == base;
+}
+
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+
+bfd_boolean
+_bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ flagword old_flags;
+ flagword new_flags;
+ bfd_boolean ok;
+ bfd_boolean null_input_bfd = TRUE;
+ asection *sec;
+
+ /* Check if we have the same endianess */
+ if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+ {
+ (*_bfd_error_handler)
+ (_("%B: endianness incompatible with that of the selected emulation"),
+ ibfd);
+ return FALSE;
+ }
+
+ if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
+ return TRUE;
+
+ if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
+ {
+ (*_bfd_error_handler)
+ (_("%B: ABI is incompatible with that of the selected emulation"),
+ ibfd);
+ return FALSE;
+ }
+
+ if (!_bfd_elf_merge_object_attributes (ibfd, obfd))
+ return FALSE;
+
+ new_flags = elf_elfheader (ibfd)->e_flags;
+ old_flags = elf_elfheader (obfd)->e_flags;
+
+ if (! elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = new_flags;
+ elf_elfheader (obfd)->e_ident[EI_CLASS]
+ = elf_elfheader (ibfd)->e_ident[EI_CLASS];
+
+ if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+ && (bfd_get_arch_info (obfd)->the_default
+ || mips_mach_extends_p (bfd_get_mach (obfd),
+ bfd_get_mach (ibfd))))
+ {
+ if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd)))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /* Check flag compatibility. */
+
+ if (new_flags == old_flags)
+ return TRUE;
+
+ /* Check to see if the input BFD actually contains any sections.
+ If not, its flags may not have been initialised either, but it cannot
+ actually cause any incompatibility. */
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ /* Ignore synthetic sections and empty .text, .data and .bss sections
+ which are automatically generated by gas. Also ignore fake
+ (s)common sections, since merely defining a common symbol does
+ not affect compatibility. */
+ if ((sec->flags & SEC_IS_COMMON) == 0
+ && (sec->size != 0
+ || (strcmp (sec->name, ".text")
+ && strcmp (sec->name, ".data")
+ && strcmp (sec->name, ".bss"))))
+ {
+ null_input_bfd = FALSE;
+ break;
+ }
+ }
+ if (null_input_bfd)
+ return TRUE;
+
+ ok = TRUE;
+
+ /* Don't link RV32 and RV64. */
+ if (elf_elfheader (ibfd)->e_ident[EI_CLASS]
+ != elf_elfheader (obfd)->e_ident[EI_CLASS])
+ {
+ (*_bfd_error_handler)
+ (_("%B: ABI mismatch: linking %s module with previous %s modules"),
+ ibfd,
+ elf_mips_abi_name (ibfd),
+ elf_mips_abi_name (obfd));
+ ok = FALSE;
+ }
+
+ /* Warn about any other mismatches */
+ if (new_flags != old_flags)
+ {
+ if (!EF_IS_RISCV_EXT_Xcustom(new_flags) &&
+ !EF_IS_RISCV_EXT_Xcustom(old_flags)) {
+ (*_bfd_error_handler)
+ (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+ ibfd, (unsigned long) new_flags,
+ (unsigned long) old_flags);
+ ok = FALSE;
+ } else if (EF_IS_RISCV_EXT_Xcustom(new_flags)) {
+ EF_SET_RISCV_EXT(elf_elfheader (obfd)->e_flags, EF_GET_RISCV_EXT(old_flags));
+ }
+ }
+
+ if (! ok)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+char *
+_bfd_riscv_elf_get_target_dtag (bfd_vma dtag)
+{
+ switch (dtag)
+ {
+ case DT_RISCV_LOCAL_GOTNO:
+ return "MIPS_LOCAL_GOTNO";
+ case DT_RISCV_SYMTABNO:
+ return "MIPS_SYMTABNO";
+ case DT_RISCV_GOTSYM:
+ return "MIPS_GOTSYM";
+ case DT_RISCV_PLTGOT:
+ return "DT_RISCV_PLTGOT";
+ default:
+ return "";
+ }
+}
+
+bfd_boolean
+_bfd_riscv_elf_print_private_bfd_data (bfd *abfd, void *ptr)
+{
+ FILE *file = ptr;
+
+ BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+ /* Print normal ELF private data. */
+ _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+ /* xgettext:c-format */
+ fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+
+ if (ABI_32_P (abfd))
+ fprintf (file, _(" [rv32]"));
+ else if (ABI_64_P (abfd))
+ fprintf (file, _(" [rv64]"));
+ else
+ fprintf (file, _(" [no abi set]"));
+
+ fputc ('\n', file);
+
+ return TRUE;
+}
+
+const struct bfd_elf_special_section _bfd_riscv_elf_special_sections[] =
+{
+ { NULL, 0, 0, 0, 0 }
+};
+
+/* Merge non visibility st_other attributes. Ensure that the
+ STO_OPTIONAL flag is copied into h->other, even if this is not a
+ definiton of the symbol. */
+void
+_bfd_riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
+ const Elf_Internal_Sym *isym,
+ bfd_boolean definition,
+ bfd_boolean dynamic ATTRIBUTE_UNUSED)
+{
+ if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0)
+ {
+ unsigned char other;
+
+ other = (definition ? isym->st_other : h->other);
+ other &= ~ELF_ST_VISIBILITY (-1);
+ h->other = other | ELF_ST_VISIBILITY (h->other);
+ }
+}
+
+bfd_boolean
+_bfd_riscv_elf_common_definition (Elf_Internal_Sym *sym)
+{
+ return (sym->st_shndx == SHN_COMMON);
+}
+
+/* Delete some bytes from a section while relaxing. */
+
+static bfd_boolean
+riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count)
+{
+ Elf_Internal_Shdr * symtab_hdr;
+ unsigned int sec_shndx;
+ bfd_byte * contents;
+ Elf_Internal_Rela * irel;
+ Elf_Internal_Rela * irelend;
+ Elf_Internal_Sym * isym;
+ Elf_Internal_Sym * isymend;
+ bfd_vma toaddr;
+ unsigned int symcount;
+ struct elf_link_hash_entry ** sym_hashes;
+ struct elf_link_hash_entry ** end_hashes;
+
+ /* TODO: handle alignment */
+ Elf_Internal_Rela *alignment_rel = NULL;
+
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ /* The deletion must stop at the next alignment boundary, if
+ ALIGNMENT_REL is non-NULL. */
+ toaddr = sec->size;
+ if (alignment_rel)
+ toaddr = alignment_rel->r_offset;
+
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+
+ /* Actually delete the bytes. */
+ memmove (contents + addr, contents + addr + count,
+ (size_t) (toaddr - addr - count));
+
+ if (alignment_rel)
+ {
+ size_t i;
+ BFD_ASSERT (count % 4 == 0);
+ for (i = 0; i < count; i += 4)
+ bfd_put_32 (abfd, RISCV_NOP, contents + toaddr - count + i);
+ /* TODO: RVC NOP if count % 4 == 2 */
+ }
+ else
+ sec->size -= count;
+
+ /* Adjust all the relocs. */
+ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ {
+ if (irel->r_offset <= addr)
+ {
+ if (irel->r_offset + irel->r_addend > addr)
+ irel->r_addend -= ELF_R_SYM (abfd, irel->r_info) ? 0 : count;
+ }
+ else
+ {
+ if (irel->r_offset + irel->r_addend <= addr)
+ irel->r_addend += ELF_R_SYM (abfd, irel->r_info) ? 0 : count;
+ if (irel->r_offset < toaddr)
+ irel->r_offset -= count;
+ }
+ }
+
+ /* Adjust the local symbols defined in this section. */
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ isymend = isym + symtab_hdr->sh_info;
+
+ for (; isym < isymend; isym++)
+ {
+ /* If the symbol is in the range of memory we just moved, we
+ have to adjust its value. */
+ if (isym->st_shndx == sec_shndx
+ && isym->st_value > addr
+ && isym->st_value <= toaddr)
+ isym->st_value -= count;
+
+ /* If the symbol *spans* the bytes we just deleted (i.e. its
+ *end* is in the moved bytes but its *start* isn't), then we
+ must adjust its size. */
+ if (isym->st_shndx == sec_shndx
+ && isym->st_value < addr
+ && isym->st_value + isym->st_size > addr
+ && isym->st_value + isym->st_size <= toaddr)
+ isym->st_size -= count;
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ symcount = symtab_hdr->sh_size / sizeof(Elf64_External_Sym);
+ if (!ABI_64_P (abfd))
+ symcount = symtab_hdr->sh_size / sizeof(Elf32_External_Sym);
+ symcount -= symtab_hdr->sh_info;
+
+ sym_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ /* As above, adjust the value if needed. */
+ if (sym_hash->root.u.def.value > addr
+ && sym_hash->root.u.def.value < toaddr)
+ sym_hash->root.u.def.value -= count;
+
+ /* As above, adjust the size if needed. */
+ if (sym_hash->root.u.def.value < addr
+ && sym_hash->root.u.def.value + sym_hash->size > addr
+ && sym_hash->root.u.def.value + sym_hash->size < toaddr)
+ sym_hash->size -= count;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_riscv_relax_call (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ Elf_Internal_Sym *isymbuf,
+ Elf_Internal_Rela *internal_relocs,
+ Elf_Internal_Rela *irel, bfd_vma symval,
+ bfd_boolean *again)
+{
+ /* See if this function call can be shortened. */
+ bfd_signed_vma foff = symval - (sec_addr(sec) + irel->r_offset);
+ bfd_boolean near_zero = !link_info->shared && symval < RISCV_IMM_REACH/2;
+ if (!VALID_UJTYPE_IMM (foff) && !near_zero)
+ return TRUE;
+
+ /* Shorten the function call. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ BFD_ASSERT (irel->r_offset + 8 <= sec->size);
+
+ bfd_vma auipc = bfd_get_32 (abfd, contents + irel->r_offset);
+ BFD_ASSERT ((auipc & MASK_AUIPC) == MATCH_AUIPC);
+
+ bfd_vma jalr = bfd_get_32 (abfd, contents + irel->r_offset + 4);
+ BFD_ASSERT ((jalr & MASK_JALR) == MATCH_JALR);
+ /* Replace the R_RISCV_CALL reloc with R_RISCV_JAL. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_JAL);
+ /* Overwrite AUIPC with JAL rd, addr. */
+ auipc = (jalr & (OP_MASK_RD << OP_SH_RD)) | MATCH_JAL;
+ bfd_put_32 (abfd, auipc, contents + irel->r_offset);
+
+ /* Delete unnecessary JALR. */
+ if (! riscv_relax_delete_bytes (abfd, sec, irel->r_offset + 4, 4))
+ return FALSE;
+
+ *again = TRUE;
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_riscv_relax_lui (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ Elf_Internal_Sym *isymbuf,
+ Elf_Internal_Rela *internal_relocs,
+ Elf_Internal_Rela *irel, bfd_vma symval,
+ bfd_boolean *again)
+{
+ bfd_vma gp = bfd_riscv_init_gp_value (abfd, link_info);
+ if (!gp || symval == gp)
+ return TRUE;
+
+ /* See if this symbol is in range of gp. */
+ if (RISCV_CONST_HIGH_PART (symval - gp) != 0)
+ return TRUE;
+
+ /* We can delete the unnecessary AUIPC. The corresponding LO12 reloc
+ will be converted to GPREL during relocation. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ BFD_ASSERT (irel->r_offset + 4 <= sec->size);
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_NONE);
+ if (! riscv_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
+ return FALSE;
+
+ *again = TRUE;
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_riscv_relax_tls_le (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ Elf_Internal_Sym *isymbuf,
+ Elf_Internal_Rela *internal_relocs,
+ Elf_Internal_Rela *irel, bfd_vma symval,
+ bfd_boolean *again)
+{
+ /* See if this symbol is in range of tp. */
+ if (RISCV_CONST_HIGH_PART (symval - tprel_base (link_info)) != 0)
+ return TRUE;
+
+ /* We can delete the unnecessary LUI and TP add. The LO12 reloc will be
+ made directly TP-relative. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ BFD_ASSERT (irel->r_offset + 4 <= sec->size);
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_NONE);
+ if (! riscv_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
+ return FALSE;
+
+ *again = TRUE;
+ return TRUE;
+}
+
+/* Relax TLS IE to TLS LE. */
+static bfd_boolean
+_bfd_riscv_relax_tls_ie (bfd *abfd, asection *sec,
+ bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ Elf_Internal_Sym *isymbuf,
+ Elf_Internal_Rela *internal_relocs,
+ Elf_Internal_Rela *irel,
+ bfd_boolean *again)
+{
+ bfd_vma insn;
+
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ switch (ELF_R_TYPE (abfd, irel->r_info))
+ {
+ case R_RISCV_TLS_IE_HI20:
+ /* Replace with R_RISCV_TPREL_HI20. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_TPREL_HI20);
+ /* Overwrite AUIPC with LUI. */
+ BFD_ASSERT (irel->r_offset + 4 <= sec->size);
+ insn = bfd_get_32 (abfd, contents + irel->r_offset);
+ insn = (insn & ~MASK_LUI) | MATCH_LUI;
+ bfd_put_32 (abfd, insn, contents + irel->r_offset);
+ break;
+
+ case R_RISCV_TLS_IE_LO12:
+ /* Just delete the reloc. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_NONE);
+ if (! riscv_relax_delete_bytes (abfd, sec, irel->r_offset, 4))
+ return FALSE;
+ break;
+
+ case R_RISCV_TLS_IE_ADD:
+ /* Replace with R_RISCV_TPREL_ADD. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_TPREL_ADD);
+ break;
+
+ case R_RISCV_TLS_IE_LO12_I:
+ /* Replace with R_RISCV_TPREL_LO12_I. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_TPREL_LO12_I);
+ break;
+
+ case R_RISCV_TLS_IE_LO12_S:
+ /* Replace with R_RISCV_TPREL_LO12_S. */
+ irel->r_info = ELF_R_INFO (abfd, ELF_R_SYM (abfd, irel->r_info), R_RISCV_TPREL_LO12_S);
+ break;
+
+ default:
+ abort();
+ }
+
+ *again = TRUE;
+ return TRUE;
+}
+
+/* Relax AUIPC/JALR into JAL. */
+
+bfd_boolean
+_bfd_riscv_relax_section (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info, bfd_boolean *again)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *internal_relocs;
+ Elf_Internal_Rela *irel, *irelend;
+ bfd_byte *contents = NULL;
+ Elf_Internal_Sym *isymbuf = NULL;
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (link_info);
+ htab->relax = TRUE;
+
+ *again = FALSE;
+
+ if (link_info->relocatable
+ || (sec->flags & SEC_RELOC) == 0
+ || sec->reloc_count == 0)
+ return TRUE;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+
+ internal_relocs = (_bfd_elf_link_read_relocs
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
+ link_info->keep_memory));
+ if (internal_relocs == NULL)
+ goto error_return;
+
+ irelend = internal_relocs + sec->reloc_count;
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ bfd_vma symval;
+ int type = ELF_R_TYPE (abfd, irel->r_info);
+ bfd_boolean call = type == R_RISCV_CALL || type == R_RISCV_CALL_PLT;
+ bfd_boolean lui = type == R_RISCV_HI20 || type == R_RISCV_PCREL_HI20;
+ bfd_boolean tls_le = type == R_RISCV_TPREL_HI20 || type == R_RISCV_TPREL_ADD;
+ bfd_boolean tls_ie = type == R_RISCV_TLS_IE_HI20 || type == R_RISCV_TLS_IE_LO12 || type == R_RISCV_TLS_IE_ADD || type == R_RISCV_TLS_IE_LO12_I || type == R_RISCV_TLS_IE_LO12_S;
+
+ if (!(call || lui || tls_le || tls_ie))
+ continue;
+
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ goto error_return;
+ }
+ }
+
+ /* Read this BFD's symbols if we haven't done so already. */
+ if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ goto error_return;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF_R_SYM (abfd, irel->r_info) < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ Elf_Internal_Sym *isym = isymbuf + ELF_R_SYM (abfd, irel->r_info);
+
+ if (isym->st_shndx == SHN_UNDEF)
+ symval = sec_addr(sec) + irel->r_offset;
+ else
+ {
+ asection *isec;
+ BFD_ASSERT (isym->st_shndx < elf_numsections (abfd));
+ isec = elf_elfsections (abfd)[isym->st_shndx]->bfd_section;
+ symval = sec_addr(isec) + isym->st_value;
+ }
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+
+ indx = ELF_R_SYM (abfd, irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->plt.offset != MINUS_ONE)
+ symval = sec_addr(htab->splt) + h->plt.offset;
+ else if (h->root.u.def.section->output_section == NULL
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak))
+ continue;
+ else
+ symval = sec_addr(h->root.u.def.section) + h->root.u.def.value;
+ }
+
+ symval += irel->r_addend;
+
+ if (call && !_bfd_riscv_relax_call (abfd, sec, link_info, contents,
+ symtab_hdr, isymbuf, internal_relocs,
+ irel, symval, again))
+ goto error_return;
+ if (lui && !_bfd_riscv_relax_lui (abfd, sec, link_info, contents,
+ symtab_hdr, isymbuf, internal_relocs,
+ irel, symval, again))
+ goto error_return;
+ if (tls_le && !_bfd_riscv_relax_tls_le (abfd, sec, link_info, contents,
+ symtab_hdr, isymbuf, internal_relocs,
+ irel, symval, again))
+ goto error_return;
+ if (tls_ie && !_bfd_riscv_relax_tls_ie (abfd, sec, contents, symtab_hdr,
+ isymbuf, internal_relocs, irel,
+ again))
+ goto error_return;
+ }
+
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ {
+ if (! link_info->keep_memory)
+ free (isymbuf);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+ }
+ }
+
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ {
+ if (! link_info->keep_memory)
+ free (contents);
+ else
+ {
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return TRUE;
+
+ error_return:
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ free (isymbuf);
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ free (contents);
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return FALSE;
+}
diff --git a/binutils-2.21.1/bfd/elfxx-riscv.h b/binutils-2.21.1/bfd/elfxx-riscv.h
new file mode 100644
index 0000000..11c2ed8
--- /dev/null
+++ binutils-2.21.1/bfd/elfxx-riscv.h
@@ -0,0 +1,110 @@
+/* RISC-V ELF specific backend routines.
+ Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
+
+ 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 "elf/common.h"
+#include "elf/internal.h"
+#include "elf/riscv.h"
+
+extern bfd_boolean _bfd_riscv_elf_new_section_hook
+ (bfd *, asection *);
+extern void _bfd_riscv_elf_symbol_processing
+ (bfd *, asymbol *);
+extern unsigned int _bfd_riscv_elf_eh_frame_address_size
+ (bfd *, asection *);
+extern bfd_boolean _bfd_riscv_elf_fake_sections
+ (bfd *, Elf_Internal_Shdr *, asection *);
+extern bfd_boolean _bfd_riscv_elf_add_symbol_hook
+ (bfd *, struct bfd_link_info *, Elf_Internal_Sym *,
+ const char **, flagword *, asection **, bfd_vma *);
+extern bfd_boolean _bfd_riscv_elf_create_dynamic_sections
+ (bfd *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_check_relocs
+ (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+extern bfd_boolean _bfd_riscv_elf_adjust_dynamic_symbol
+ (struct bfd_link_info *, struct elf_link_hash_entry *);
+extern bfd_boolean _bfd_riscv_elf_always_size_sections
+ (bfd *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_size_dynamic_sections
+ (bfd *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_relocate_section
+ (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
+extern bfd_boolean _bfd_riscv_elf_finish_dynamic_symbol
+ (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *);
+extern bfd_boolean _bfd_riscv_elf_finish_dynamic_sections
+ (bfd *, struct bfd_link_info *);
+extern int _bfd_riscv_elf_additional_program_headers
+ (bfd *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_modify_segment_map
+ (bfd *, struct bfd_link_info *);
+extern void _bfd_riscv_elf_copy_indirect_symbol
+ (struct bfd_link_info *, struct elf_link_hash_entry *,
+ struct elf_link_hash_entry *);
+extern bfd_boolean _bfd_riscv_elf_ignore_discarded_relocs
+ (asection *);
+extern bfd_boolean _bfd_riscv_elf_find_nearest_line
+ (bfd *, asection *, asymbol **, bfd_vma, const char **,
+ const char **, unsigned int *);
+extern bfd_boolean _bfd_riscv_elf_find_inliner_info
+ (bfd *, const char **, const char **, unsigned int *);
+extern bfd_boolean _bfd_riscv_elf_set_section_contents
+ (bfd *, asection *, const void *, file_ptr, bfd_size_type);
+extern struct bfd_link_hash_table *_bfd_riscv_elf_link_hash_table_create
+ (bfd *);
+extern bfd_boolean _bfd_riscv_elf_final_link
+ (bfd *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_merge_private_bfd_data
+ (bfd *, bfd *);
+extern bfd_boolean _bfd_riscv_elf_print_private_bfd_data
+ (bfd *, void *);
+extern bfd_boolean _bfd_riscv_elf_discard_info
+ (bfd *, struct elf_reloc_cookie *, struct bfd_link_info *);
+extern bfd_boolean _bfd_riscv_elf_write_section
+ (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
+
+extern bfd_reloc_status_type _bfd_riscv_elf_generic_reloc
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+extern bfd_boolean _bfd_riscv_relax_section
+ (bfd *, asection *, struct bfd_link_info *, bfd_boolean *);
+extern void _bfd_riscv_elf_merge_symbol_attribute
+ (struct elf_link_hash_entry *, const Elf_Internal_Sym *, bfd_boolean, bfd_boolean);
+extern char *_bfd_riscv_elf_get_target_dtag (bfd_vma);
+extern void _bfd_riscv_elf_use_plts_and_copy_relocs
+ (struct bfd_link_info *);
+extern bfd_vma _bfd_riscv_elf_plt_sym_val
+ (bfd_vma, const asection *, const arelent *rel);
+
+extern const struct bfd_elf_special_section _bfd_riscv_elf_special_sections [];
+
+extern bfd_boolean _bfd_riscv_elf_common_definition (Elf_Internal_Sym *);
+extern reloc_howto_type *riscv_elf_bfd_reloc_type_lookup
+ (bfd *, bfd_reloc_code_real_type);
+extern reloc_howto_type *riscv_elf_bfd_reloc_name_lookup (bfd *, const char *);
+extern void riscv_elf_info_to_howto_rel
+ (bfd *, arelent *, Elf_Internal_Rela *);
+extern void riscv_elf_info_to_howto_rela
+ (bfd *, arelent *, Elf_Internal_Rela *);
+
+#define elf_backend_common_definition _bfd_riscv_elf_common_definition
+#define elf_backend_special_sections _bfd_riscv_elf_special_sections
+#define elf_backend_eh_frame_address_size _bfd_riscv_elf_eh_frame_address_size
+#define elf_backend_merge_symbol_attribute _bfd_riscv_elf_merge_symbol_attribute
diff --git a/binutils-2.21.1/bfd/targets.c b/binutils-2.21.1/bfd/targets.c
index 3e99754..a1f375c 100644
--- a/binutils-2.21.1/bfd/targets.c
+++ binutils-2.21.1/bfd/targets.c
@@ -624,6 +624,7 @@ extern const bfd_target bfd_elf32_littlearm_symbian_vec;
extern const bfd_target bfd_elf32_littlearm_vxworks_vec;
extern const bfd_target bfd_elf32_littlemips_vec;
extern const bfd_target bfd_elf32_littlemips_vxworks_vec;
+extern const bfd_target bfd_elf32_littleriscv_vec;
extern const bfd_target bfd_elf32_m32c_vec;
extern const bfd_target bfd_elf32_m32r_vec;
extern const bfd_target bfd_elf32_m32rle_vec;
@@ -702,6 +703,7 @@ extern const bfd_target bfd_elf64_ia64_little_vec;
extern const bfd_target bfd_elf64_ia64_vms_vec;
extern const bfd_target bfd_elf64_little_generic_vec;
extern const bfd_target bfd_elf64_littlemips_vec;
+extern const bfd_target bfd_elf64_littleriscv_vec;
extern const bfd_target bfd_elf64_mmix_vec;
extern const bfd_target bfd_elf64_powerpc_vec;
extern const bfd_target bfd_elf64_powerpcle_vec;
diff --git a/binutils-2.21.1/binutils/Makefile.am b/binutils-2.21.1/binutils/Makefile.am
index e59601d..b51d47d 100644
--- a/binutils-2.21.1/binutils/Makefile.am
+++ binutils-2.21.1/binutils/Makefile.am
@@ -267,7 +267,7 @@ sysinfo$(EXEEXT_FOR_BUILD): sysinfo.@OBJEXT@ syslex.@OBJEXT@
syslex.@OBJEXT@: syslex.c sysinfo.h config.h
if [ -r syslex.c ]; then \
- $(CC_FOR_BUILD) -c -I. $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) syslex.c ; \
+ $(CC_FOR_BUILD) -c -I. -I$(srcdir) $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) syslex.c ; \
else \
$(CC_FOR_BUILD) -c -I. -I$(srcdir) $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) $(srcdir)/syslex.c ;\
fi
diff --git a/binutils-2.21.1/binutils/Makefile.in b/binutils-2.21.1/binutils/Makefile.in
index ece74e4..4b0e76f 100644
--- a/binutils-2.21.1/binutils/Makefile.in
+++ binutils-2.21.1/binutils/Makefile.in
@@ -1279,7 +1279,7 @@ sysinfo$(EXEEXT_FOR_BUILD): sysinfo.@OBJEXT@ syslex.@OBJEXT@
syslex.@OBJEXT@: syslex.c sysinfo.h config.h
if [ -r syslex.c ]; then \
- $(CC_FOR_BUILD) -c -I. $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) syslex.c ; \
+ $(CC_FOR_BUILD) -c -I. -I$(srcdir) $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) syslex.c ; \
else \
$(CC_FOR_BUILD) -c -I. -I$(srcdir) $(AM_CFLAGS) $(CFLAGS_FOR_BUILD) $(NO_WERROR) $(srcdir)/syslex.c ;\
fi
diff --git a/binutils-2.21.1/binutils/doc/binutils.texi b/binutils-2.21.1/binutils/doc/binutils.texi
index d8d1899..448d783 100644
--- a/binutils-2.21.1/binutils/doc/binutils.texi
+++ binutils-2.21.1/binutils/doc/binutils.texi
@@ -147,18 +147,18 @@ in the section entitled ``GNU Free Documentation License''.
* objcopy:: Copy and translate object files
* objdump:: Display information from object files
* ranlib:: Generate index to archive contents
-* readelf:: Display the contents of ELF format files
* size:: List section sizes and total size
* strings:: List printable strings from files
* strip:: Discard symbols
-* elfedit:: Update the ELF header of ELF files
* c++filt:: Filter to demangle encoded C++ symbols
* cxxfilt: c++filt. MS-DOS name for c++filt
* addr2line:: Convert addresses to file and line
* nlmconv:: Converts object code into an NLM
-* windres:: Manipulate Windows resources
* windmc:: Generator for Windows message resources
+* windres:: Manipulate Windows resources
* dlltool:: Create files needed to build and use DLLs
+* readelf:: Display the contents of ELF format files
+* elfedit:: Update the ELF header of ELF files
* Common Options:: Command-line options for all utilities
* Selecting the Target System:: How these utilities determine the target
* Reporting Bugs:: Reporting Bugs
@@ -2767,7 +2767,7 @@ the Info entries for @file{binutils}.
@c man end
@end ignore
-@node c++filt, addr2line, elfedit, Top
+@node c++filt, addr2line, strip, Top
@chapter c++filt
@kindex c++filt
@@ -4190,28 +4190,28 @@ equivalent. At least one of the @option{--output-mach},
@table @env
-@itemx --input-mach=@var{machine}
+@item --input-mach=@var{machine}
Set the matching input ELF machine type to @var{machine}. If
@option{--input-mach} isn't specified, it will match any ELF
machine types.
The supported ELF machine types are, @var{L1OM} and @var{x86-64}.
-@itemx --output-mach=@var{machine}
+@item --output-mach=@var{machine}
Change the ELF machine type in the ELF header to @var{machine}. The
supported ELF machine types are the same as @option{--input-mach}.
-@itemx --input-type=@var{type}
+@item --input-type=@var{type}
Set the matching input ELF file type to @var{type}. If
@option{--input-type} isn't specified, it will match any ELF file types.
The supported ELF file types are, @var{rel}, @var{exec} and @var{dyn}.
-@itemx --output-type=@var{type}
+@item --output-type=@var{type}
Change the ELF file type in the ELF header to @var{type}. The
supported ELF types are the same as @option{--input-type}.
-@itemx --input-osabi=@var{osabi}
+@item --input-osabi=@var{osabi}
Set the matching input ELF file OSABI to @var{osbi}. If
@option{--input-osabi} isn't specified, it will match any ELF OSABIs.
@@ -4220,7 +4220,7 @@ The supported ELF OSABIs are, @var{none}, @var{HPUX}, @var{NetBSD},
@var{FreeBSD}, @var{TRU64}, @var{Modesto}, @var{OpenBSD}, @var{OpenVMS},
@var{NSK}, @var{AROS} and @var{FenixOS}.
-@itemx --output-osabi=@var{osabi}
+@item --output-osabi=@var{osabi}
Change the ELF OSABI in the ELF header to @var{type}. The
supported ELF OSABI are the same as @option{--input-osabi}.
diff --git a/binutils-2.21.1/binutils/readelf.c b/binutils-2.21.1/binutils/readelf.c
index a31dd3c..ccd9436 100644
--- a/binutils-2.21.1/binutils/readelf.c
+++ binutils-2.21.1/binutils/readelf.c
@@ -123,6 +123,7 @@
#include "elf/mep.h"
#include "elf/microblaze.h"
#include "elf/mips.h"
+#include "elf/riscv.h"
#include "elf/mmix.h"
#include "elf/mn10200.h"
#include "elf/mn10300.h"
@@ -1080,6 +1081,10 @@ dump_relocations (FILE * file,
rtype = elf_mips_reloc_type (type);
break;
+ case EM_RISCV:
+ rtype = elf_riscv_reloc_type (type);
+ break;
+
case EM_ALPHA:
rtype = elf_alpha_reloc_type (type);
break;
@@ -2405,6 +2410,14 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
strcat (buf, ", fdpic");
break;
+ case EM_RISCV:
+ {
+ unsigned int riscv_extension = EF_GET_RISCV_EXT(e_flags);
+ strcat (buf, ", ");
+ strcat (buf, riscv_elf_flag_to_name (riscv_extension));
+ }
+ break;
+
case EM_SH:
switch ((e_flags & EF_SH_MACH_MASK))
{
diff --git a/binutils-2.21.1/config.sub b/binutils-2.21.1/config.sub
index 204218c..e14dc95 100755
--- a/binutils-2.21.1/config.sub
+++ binutils-2.21.1/config.sub
@@ -323,6 +323,9 @@ case $basic_machine in
ms1)
basic_machine=mt-unknown
;;
+ riscv)
+ basic_machine=riscv-ucb
+ ;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
diff --git a/binutils-2.21.1/gas/Makefile.am b/binutils-2.21.1/gas/Makefile.am
index 7b897f3..88b27e3 100644
--- a/binutils-2.21.1/gas/Makefile.am
+++ binutils-2.21.1/gas/Makefile.am
@@ -150,6 +150,7 @@ TARGET_CPU_CFILES = \
config/tc-pdp11.c \
config/tc-pj.c \
config/tc-ppc.c \
+ config/tc-riscv.c \
config/tc-rx.c \
config/tc-s390.c \
config/tc-score.c \
@@ -213,6 +214,7 @@ TARGET_CPU_HFILES = \
config/tc-pdp11.h \
config/tc-pj.h \
config/tc-ppc.h \
+ config/tc-riscv.h \
config/tc-rx.h \
config/tc-s390.h \
config/tc-score.h \
diff --git a/binutils-2.21.1/gas/Makefile.in b/binutils-2.21.1/gas/Makefile.in
index 1aa9bb4..435df2b 100644
--- a/binutils-2.21.1/gas/Makefile.in
+++ binutils-2.21.1/gas/Makefile.in
@@ -417,6 +417,7 @@ TARGET_CPU_CFILES = \
config/tc-pdp11.c \
config/tc-pj.c \
config/tc-ppc.c \
+ config/tc-riscv.c \
config/tc-rx.c \
config/tc-s390.c \
config/tc-score.c \
@@ -480,6 +481,7 @@ TARGET_CPU_HFILES = \
config/tc-pdp11.h \
config/tc-pj.h \
config/tc-ppc.h \
+ config/tc-riscv.h \
config/tc-rx.h \
config/tc-s390.h \
config/tc-score.h \
@@ -824,6 +826,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pdp11.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pj.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-ppc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-riscv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-rx.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-s390.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-score.Po@am__quote@
@@ -1469,6 +1472,20 @@ tc-ppc.obj: config/tc-ppc.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-ppc.obj `if test -f 'config/tc-ppc.c'; then $(CYGPATH_W) 'config/tc-ppc.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-ppc.c'; fi`
+tc-riscv.o: config/tc-riscv.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-riscv.o -MD -MP -MF $(DEPDIR)/tc-riscv.Tpo -c -o tc-riscv.o `test -f 'config/tc-riscv.c' || echo '$(srcdir)/'`config/tc-riscv.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-riscv.Tpo $(DEPDIR)/tc-riscv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-riscv.c' object='tc-riscv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-riscv.o `test -f 'config/tc-riscv.c' || echo '$(srcdir)/'`config/tc-riscv.c
+
+tc-riscv.obj: config/tc-riscv.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-riscv.obj -MD -MP -MF $(DEPDIR)/tc-riscv.Tpo -c -o tc-riscv.obj `if test -f 'config/tc-riscv.c'; then $(CYGPATH_W) 'config/tc-riscv.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-riscv.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-riscv.Tpo $(DEPDIR)/tc-riscv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config/tc-riscv.c' object='tc-riscv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-riscv.obj `if test -f 'config/tc-riscv.c'; then $(CYGPATH_W) 'config/tc-riscv.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-riscv.c'; fi`
+
tc-rx.o: config/tc-rx.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rx.o -MD -MP -MF $(DEPDIR)/tc-rx.Tpo -c -o tc-rx.o `test -f 'config/tc-rx.c' || echo '$(srcdir)/'`config/tc-rx.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-rx.Tpo $(DEPDIR)/tc-rx.Po
diff --git a/binutils-2.21.1/gas/config/tc-riscv.c b/binutils-2.21.1/gas/config/tc-riscv.c
new file mode 100644
index 0000000..7a3bf45
--- /dev/null
+++ binutils-2.21.1/gas/config/tc-riscv.c
@@ -0,0 +1,3296 @@
+/* tc-mips.c -- assemble code for a MIPS chip.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Contributed by the OSF and Ralph Campbell.
+ Written by Keith Knowles and Ralph Campbell, working independently.
+ Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
+ Support.
+
+ This file is part of GAS.
+
+ GAS 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, or (at your option)
+ any later version.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "as.h"
+#include "config.h"
+#include "subsegs.h"
+#include "safe-ctype.h"
+
+#include "itbl-ops.h"
+#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
+
+#include <execinfo.h>
+#include <stdint.h>
+
+#ifdef DEBUG
+#define DBG(x) printf x
+#else
+#define DBG(x)
+#endif
+
+#ifdef OBJ_MAYBE_ELF
+/* Clean up namespace so we can include obj-elf.h too. */
+static int mips_output_flavor (void);
+static int mips_output_flavor (void) { return OUTPUT_FLAVOR; }
+#undef OBJ_PROCESS_STAB
+#undef OUTPUT_FLAVOR
+#undef S_GET_ALIGN
+#undef S_GET_SIZE
+#undef S_SET_ALIGN
+#undef S_SET_SIZE
+#undef obj_frob_file
+#undef obj_frob_file_after_relocs
+#undef obj_frob_symbol
+#undef obj_pop_insert
+#undef obj_sec_sym_ok_for_reloc
+#undef OBJ_COPY_SYMBOL_ATTRIBUTES
+
+#include "obj-elf.h"
+/* Fix any of them that we actually care about. */
+#undef OUTPUT_FLAVOR
+#define OUTPUT_FLAVOR mips_output_flavor()
+#endif
+
+#if defined (OBJ_ELF)
+#include "elf/riscv.h"
+#endif
+
+#include "opcode/riscv.h"
+
+#define ZERO 0
+#define SP 14
+
+/* Information about an instruction, including its format, operands
+ and fixups. */
+struct mips_cl_insn
+{
+ /* The opcode's entry in riscv_opcodes or mips16_opcodes. */
+ const struct riscv_opcode *insn_mo;
+
+ /* The 16-bit or 32-bit bitstring of the instruction itself. This is
+ a copy of INSN_MO->match with the operands filled in. */
+ insn_t insn_opcode;
+
+ /* The frag that contains the instruction. */
+ struct frag *frag;
+
+ /* The offset into FRAG of the first instruction byte. */
+ long where;
+
+ /* The relocs associated with the instruction, if any. */
+ fixS *fixp;
+};
+
+static bfd_boolean rv64 = TRUE; /* RV64 (true) or RV32 (false) */
+#define HAVE_32BIT_SYMBOLS 1 /* LUI/ADDI for symbols, even in RV64 */
+#define HAVE_32BIT_ADDRESSES (!rv64)
+#define LOAD_ADDRESS_INSN (HAVE_32BIT_ADDRESSES ? "lw" : "ld")
+#define ADD32_INSN (rv64 ? "addiw" : "addi")
+
+struct riscv_subset
+{
+ const char* name;
+ int version_major;
+ int version_minor;
+
+ struct riscv_subset* next;
+};
+
+static struct riscv_subset* riscv_subsets;
+
+static int
+riscv_subset_supports(const char* feature)
+{
+ struct riscv_subset* s;
+ bfd_boolean rv64_insn;
+
+ if ((rv64_insn = !strncmp(feature, "64", 2)) || !strncmp(feature, "32", 2))
+ {
+ if (rv64 != rv64_insn)
+ return 0;
+ feature += 2;
+ }
+
+ for (s = riscv_subsets; s != NULL; s = s->next)
+ if (strcmp(s->name, feature) == 0)
+ /* FIXME: once we support version numbers:
+ return major == s->version_major && minor <= s->version_minor; */
+ return 1;
+
+ return 0;
+}
+
+static void
+riscv_add_subset(const char* subset)
+{
+ struct riscv_subset* s = xmalloc(sizeof(struct riscv_subset));
+ s->name = xstrdup(subset);
+ s->version_major = 1;
+ s->version_minor = 0;
+ s->next = riscv_subsets;
+ riscv_subsets = s;
+}
+
+static void
+riscv_set_arch(const char* arg)
+{
+ /* Formally, ISA subset names begin with RV, RV32, or RV64, but we allow the
+ prefix to be omitted. We also allow all-lowercase names if version
+ numbers and eXtensions are omitted (i.e. only some combination of imafd
+ is supported in this case).
+
+ FIXME: Version numbers are not supported yet. */
+ const char* subsets = "IMAFD";
+ const char* p;
+
+ for (p = arg; *p; p++)
+ if (!ISLOWER(*p) || strchr(subsets, TOUPPER(*p)) == NULL)
+ break;
+
+ if (!*p)
+ {
+ /* Legal all-lowercase name. */
+ for (p = arg; *p; p++)
+ {
+ char subset[2] = {TOUPPER(*p), 0};
+ riscv_add_subset(subset);
+ }
+ return;
+ }
+
+ if (strncmp(arg, "RV32", 4) == 0)
+ {
+ rv64 = FALSE;
+ arg += 4;
+ }
+ else if (strncmp(arg, "RV64", 4) == 0)
+ {
+ rv64 = TRUE;
+ arg += 4;
+ }
+ else if (strncmp(arg, "RV", 2) == 0)
+ arg += 2;
+
+ if (*arg && *arg != 'I')
+ as_fatal("`I' must be the first ISA subset name specified (got %c)", *arg);
+
+ for (p = arg; *p; p++)
+ {
+ if (*p == 'X')
+ {
+ const char* q = p+1;
+ while (ISLOWER(*q))
+ q++;
+
+ char subset[q-p+1];
+ memcpy(subset, p, q-p);
+ subset[q-p] = 0;
+
+ riscv_add_subset(subset);
+ p = q-1;
+ }
+ else if (strchr(subsets, *p) != NULL)
+ {
+ char subset[2] = {*p, 0};
+ riscv_add_subset(subset);
+ }
+ else
+ as_fatal("unsupported ISA subset %c", *p);
+ }
+}
+
+/* This is the set of options which may be modified by the .set
+ pseudo-op. We use a struct so that .set push and .set pop are more
+ reliable. */
+
+struct mips_set_options
+{
+ /* Enable RVC instruction compression */
+ int rvc;
+};
+
+static struct mips_set_options mips_opts =
+{
+ /* rvc */ 0
+};
+
+/* Whether or not we're generating position-independent code. */
+static bfd_boolean is_pic = FALSE;
+
+/* handle of the OPCODE hash table */
+static struct hash_control *op_hash = NULL;
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful */
+const char comment_chars[] = "#";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that C style comments are always supported. */
+const char line_comment_chars[] = "#";
+
+/* This array holds machine specific line separator characters. */
+const char line_separator_chars[] = ";";
+
+/* Chars that can be used to separate mant from exp in floating point nums */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant */
+/* As in 0f12.456 */
+/* or 0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+ changed in read.c . Ideally it shouldn't have to know about it at all,
+ but nothing is ideal around here.
+ */
+
+static char *insn_error;
+
+static int auto_align = 1;
+
+/* To output NOP instructions correctly, we need to keep information
+ about the previous two instructions. */
+
+/* Debugging level. -g sets this to 2. -gN sets this to N. -g0 is
+ equivalent to seeing no -g option at all. */
+static int mips_debug = 0;
+
+/* For ECOFF and ELF, relocations against symbols are done in two
+ parts, with a HI relocation and a LO relocation. Each relocation
+ has only 16 bits of space to store an addend. This means that in
+ order for the linker to handle carries correctly, it must be able
+ to locate both the HI and the LO relocation. This means that the
+ relocations must appear in order in the relocation table.
+
+ In order to implement this, we keep track of each unmatched HI
+ relocation. We then sort them so that they immediately precede the
+ corresponding LO relocation. */
+
+struct mips_hi_fixup
+{
+ /* Next HI fixup. */
+ struct mips_hi_fixup *next;
+ /* This fixup. */
+ fixS *fixp;
+ /* The section this fixup is in. */
+ segT seg;
+};
+
+
+#define RELAX_BRANCH_ENCODE(uncond, rvc, toofar) \
+ ((relax_substateT) \
+ (0xc0000000 \
+ | ((rvc) ? 1 : 0) \
+ | ((toofar) ? 2 : 0) \
+ | ((uncond) ? 8 : 0)))
+#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
+#define RELAX_BRANCH_TOOFAR(i) (((i) & 2) != 0)
+#define RELAX_BRANCH_RVC(i) (((i) & 1) != 0)
+
+/* Is the given value a sign-extended 32-bit value? */
+#define IS_SEXT_32BIT_NUM(x) \
+ (((x) &~ (offsetT) 0x7fffffff) == 0 \
+ || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
+
+#define IS_SEXT_NBIT_NUM(x,n) \
+ ({ int64_t __tmp = (x); \
+ __tmp = (__tmp << (64-(n))) >> (64-(n)); \
+ __tmp == (x); })
+
+/* Is the given value a zero-extended 32-bit value? Or a negated one? */
+#define IS_ZEXT_32BIT_NUM(x) \
+ (((x) &~ (offsetT) 0xffffffff) == 0 \
+ || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
+
+/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in
+ VALUE << SHIFT. VALUE is evaluated exactly once. */
+#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \
+ (STRUCT) = (((STRUCT) & ~((MASK) << (SHIFT))) \
+ | (((VALUE) & (MASK)) << (SHIFT)))
+
+/* Extract bits MASK << SHIFT from STRUCT and shift them right
+ SHIFT places. */
+#define EXTRACT_BITS(STRUCT, MASK, SHIFT) \
+ (((STRUCT) >> (SHIFT)) & (MASK))
+
+/* Change INSN's opcode so that the operand given by FIELD has value VALUE.
+ INSN is a mips_cl_insn structure and VALUE is evaluated exactly once. */
+#define INSERT_OPERAND(FIELD, INSN, VALUE) \
+ INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)
+
+/* Extract the operand given by FIELD from mips_cl_insn INSN. */
+#define EXTRACT_OPERAND(FIELD, INSN) \
+ EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)
+
+/* Determine if an instruction matches an opcode. */
+#define OPCODE_MATCHES(OPCODE, OP) \
+ (((OPCODE) & MASK_##OP) == MATCH_##OP)
+
+#define INSN_MATCHES(INSN, OP) \
+ (((INSN).insn_opcode & MASK_##OP) == MATCH_##OP)
+
+/* Prototypes for static functions. */
+
+#define internalError() \
+ as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
+
+enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG };
+
+static void append_insn
+ (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type r);
+static void macro (struct mips_cl_insn * ip);
+static void mips_ip (char *str, struct mips_cl_insn * ip);
+static void my_getExpression (expressionS *, char *);
+static void s_align (int);
+static void s_change_sec (int);
+static void s_change_section (int);
+static void s_cons (int);
+static void s_float_cons (int);
+static void s_riscv_option (int);
+static void s_dtprelword (int);
+static void s_dtpreldword (int);
+static int validate_mips_insn (const struct riscv_opcode *);
+static int relaxed_branch_length (fragS *fragp, asection *sec, int update);
+
+/* Pseudo-op table.
+
+ The following pseudo-ops from the Kane and Heinrich MIPS book
+ should be defined here, but are currently unsupported: .alias,
+ .galive, .gjaldef, .gjrlive, .livereg, .noalias.
+
+ The following pseudo-ops from the Kane and Heinrich MIPS book are
+ specific to the type of debugging information being generated, and
+ should be defined by the object format: .aent, .begin, .bend,
+ .bgnb, .end, .endb, .ent, .fmask, .frame, .loc, .mask, .verstamp,
+ .vreg.
+
+ The following pseudo-ops from the Kane and Heinrich MIPS book are
+ not MIPS CPU specific, but are also not specific to the object file
+ format. This file is probably the best place to define them, but
+ they are not currently supported: .asm0, .endr, .lab, .struct. */
+
+static const pseudo_typeS mips_pseudo_table[] =
+{
+ /* MIPS specific pseudo-ops. */
+ {"option", s_riscv_option, 0},
+ {"rdata", s_change_sec, 'r'},
+ {"dtprelword", s_dtprelword, 0},
+ {"dtpreldword", s_dtpreldword, 0},
+
+ /* Relatively generic pseudo-ops that happen to be used on MIPS
+ chips. */
+ {"asciiz", stringer, 8 + 1},
+ {"bss", s_change_sec, 'b'},
+ {"err", s_err, 0},
+ {"half", s_cons, 1},
+ {"dword", s_cons, 3},
+ {"origin", s_org, 0},
+ {"repeat", s_rept, 0},
+
+ /* leb128 doesn't work with relaxation; disallow it */
+ {"uleb128", s_err, 0},
+ {"sleb128", s_err, 0},
+
+ /* These pseudo-ops are defined in read.c, but must be overridden
+ here for one reason or another. */
+ {"align", s_align, 0},
+ {"byte", s_cons, 0},
+ {"data", s_change_sec, 'd'},
+ {"double", s_float_cons, 'd'},
+ {"float", s_float_cons, 'f'},
+ {"globl", s_globl, 0},
+ {"global", s_globl, 0},
+ {"hword", s_cons, 1},
+ {"int", s_cons, 2},
+ {"long", s_cons, 2},
+ {"octa", s_cons, 4},
+ {"quad", s_cons, 3},
+ {"section", s_change_section, 0},
+ {"short", s_cons, 1},
+ {"single", s_float_cons, 'f'},
+ {"text", s_change_sec, 't'},
+ {"word", s_cons, 2},
+
+ {"bgnb", s_ignore, 0},
+ {"endb", s_ignore, 0},
+ {"file", (void (*) (int)) dwarf2_directive_file, 0 },
+ {"loc", dwarf2_directive_loc, 0 },
+ {"verstamp", s_ignore, 0},
+
+ { NULL, NULL, 0 },
+};
+
+extern void pop_insert (const pseudo_typeS *);
+
+void
+mips_pop_insert (void)
+{
+ pop_insert (mips_pseudo_table);
+}
+
+/* Symbols labelling the current insn. */
+
+struct insn_label_list
+{
+ struct insn_label_list *next;
+ symbolS *label;
+};
+
+static struct insn_label_list *free_insn_labels;
+#define label_list tc_segment_info_data.labels
+
+void
+mips_clear_insn_labels (void)
+{
+ register struct insn_label_list **pl;
+ segment_info_type *si;
+
+ if (now_seg)
+ {
+ for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
+ ;
+
+ si = seg_info (now_seg);
+ *pl = si->label_list;
+ si->label_list = NULL;
+ }
+}
+
+
+static char *expr_end;
+
+/* Expressions which appear in instructions. These are set by
+ mips_ip. */
+
+static expressionS imm_expr;
+static expressionS offset_expr;
+
+/* Relocs associated with imm_expr and offset_expr. */
+
+static bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
+static bfd_reloc_code_real_type offset_reloc = BFD_RELOC_UNUSED;
+
+/* The default target format to use. */
+
+const char *
+mips_target_format (void)
+{
+ return rv64 ? "elf64-littleriscv" : "elf32-littleriscv";
+}
+
+/* Return the length of instruction INSN. */
+
+static inline unsigned int
+insn_length (const struct mips_cl_insn *insn)
+{
+ return riscv_insn_length (insn->insn_opcode);
+}
+
+#if 0
+static int
+imm_bits_needed(int32_t imm)
+{
+ int imm_bits = 32;
+ while(imm_bits > 1 && (imm << (32-(imm_bits-1)) >> (32-(imm_bits-1))) == imm)
+ imm_bits--;
+ return imm_bits;
+}
+
+/* return the rvc small register id, if it exists; else, return -1. */
+#define ARRAY_FIND(array, x) ({ \
+ size_t _pos = ARRAY_SIZE(array), _i; \
+ for(_i = 0; _i < ARRAY_SIZE(array); _i++) \
+ if((x) == (array)[_i]) \
+ { _pos = _i; break; } \
+ _pos; })
+#define IN_ARRAY(array, x) (ARRAY_FIND(array, x) != ARRAY_SIZE(array))
+
+#define is_rvc_reg(type, x) IN_ARRAY(rvc_##type##_regmap, x)
+#define rvc_reg(type, x) ARRAY_FIND(rvc_##type##_regmap, x)
+
+/* If insn can be compressed, compress it and return 1; else return 0. */
+static int
+riscv_rvc_compress(struct mips_cl_insn* insn)
+{
+ int rd = EXTRACT_OPERAND(RD, *insn);
+ int rs1 = EXTRACT_OPERAND(RS1, *insn);
+ int rs2 ATTRIBUTE_UNUSED = EXTRACT_OPERAND(RS2, *insn);
+ int32_t imm = EXTRACT_OPERAND(IMMEDIATE, *insn);
+ imm = imm << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS);
+ int32_t shamt = imm & 0x3f;
+ int32_t bimm = EXTRACT_OPERAND(IMMLO, *insn) |
+ (EXTRACT_OPERAND(IMMHI, *insn) << RISCV_IMMLO_BITS);
+ bimm = bimm << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS);
+ int32_t jt = EXTRACT_OPERAND(TARGET, *insn);
+ jt = jt << (32-RISCV_JUMP_BITS) >> (32-RISCV_JUMP_BITS);
+
+ gas_assert(insn_length(insn) == 4);
+
+ int imm_bits = imm_bits_needed(imm);
+ int bimm_bits = imm_bits_needed(bimm);
+ int jt_bits = imm_bits_needed(jt);
+
+ if(INSN_MATCHES(*insn, ADDI) && rd != 0 && rd == rs1 && imm_bits <= 6)
+ {
+ insn->insn_opcode = MATCH_C_ADDI;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm);
+ }
+ else if(INSN_MATCHES(*insn, ADDIW) && rd != 0 && rd == rs1 && imm_bits <= 6)
+ {
+ insn->insn_opcode = MATCH_C_ADDIW;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm);
+ }
+ else if(INSN_MATCHES(*insn, JALR) && rd == 0 && imm == 0)
+ {
+ // jalr rd=0, imm=0 is encoded as c.addi rd=0, imm={1'b0,rs1}
+ insn->insn_opcode = MATCH_C_ADDI;
+ INSERT_OPERAND(CIMM6, *insn, rs1);
+ }
+ else if(INSN_MATCHES(*insn, JALR) && rd == 1 && imm == 0)
+ {
+ // jalr rd=1, rs1, imm=0 is encoded as c.addi rd=0, imm={1'b1,rs1}
+ insn->insn_opcode = MATCH_C_ADDI;
+ INSERT_OPERAND(CIMM6, *insn, 0x20 | rs1);
+ }
+ else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) ||
+ INSN_MATCHES(*insn, XORI)) && rs1 == 0 && imm_bits <= 6)
+ {
+ insn->insn_opcode = MATCH_C_LI;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm);
+ }
+ else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) ||
+ INSN_MATCHES(*insn, XORI)) && rs1 == 0 && imm_bits <= 6)
+ {
+ insn->insn_opcode = MATCH_C_LI;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm);
+ }
+ else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) ||
+ INSN_MATCHES(*insn, XORI)) && imm == 0)
+ {
+ insn->insn_opcode = MATCH_C_MOVE;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CRS1, *insn, rs1);
+ }
+ else if((INSN_MATCHES(*insn, ADD) || INSN_MATCHES(*insn, OR) ||
+ INSN_MATCHES(*insn, XOR)) &&
+ (rs1 == 0 || rs2 == 0))
+ {
+ insn->insn_opcode = MATCH_C_MOVE;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CRS1, *insn, rs1 == 0 ? rs2 : rs1);
+ }
+ else if(INSN_MATCHES(*insn, ADD) && (rd == rs1 || rd == rs2))
+ {
+ insn->insn_opcode = MATCH_C_ADD;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CRS1, *insn, rd == rs1 ? rs2 : rs1);
+ }
+ else if(INSN_MATCHES(*insn, SUB) && rd == rs2)
+ {
+ insn->insn_opcode = MATCH_C_SUB;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CRS1, *insn, rs1);
+ }
+ else if(INSN_MATCHES(*insn, ADD) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2))
+ {
+ insn->insn_opcode = MATCH_C_ADD3;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2));
+ }
+ else if(INSN_MATCHES(*insn, SUB) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2))
+ {
+ insn->insn_opcode = MATCH_C_SUB3;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2));
+ }
+ else if(INSN_MATCHES(*insn, OR) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2))
+ {
+ insn->insn_opcode = MATCH_C_OR3;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2));
+ }
+ else if(INSN_MATCHES(*insn, AND) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2))
+ {
+ insn->insn_opcode = MATCH_C_AND3;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2));
+ }
+ else if(INSN_MATCHES(*insn, SLLI) && rd == rs1 && is_rvc_reg(rd, rd))
+ {
+ insn->insn_opcode = shamt >= 32 ? MATCH_C_SLLI32 : MATCH_C_SLLI;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, shamt);
+ }
+ else if(INSN_MATCHES(*insn, SRLI) && rd == rs1 && is_rvc_reg(rd, rd))
+ {
+ insn->insn_opcode = shamt >= 32 ? MATCH_C_SRLI32 : MATCH_C_SRLI;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, shamt);
+ }
+ else if(INSN_MATCHES(*insn, SRAI) && rd == rs1 && is_rvc_reg(rd, rd))
+ {
+ insn->insn_opcode = shamt >= 32 ? MATCH_C_SRAI32 : MATCH_C_SRAI;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, shamt);
+ }
+ else if(INSN_MATCHES(*insn, SLLIW) && rd == rs1 && is_rvc_reg(rd, rd))
+ {
+ insn->insn_opcode = MATCH_C_SLLIW;
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, shamt);
+ }
+ else if(INSN_MATCHES(*insn, JAL) && rd == 0 && jt_bits <= 10)
+ {
+ insn->insn_opcode = MATCH_C_J;
+ INSERT_OPERAND(CIMM10, *insn, jt);
+ }
+ else if(INSN_MATCHES(*insn, BEQ) && rs1 == rs2 && bimm_bits <= 10)
+ {
+ insn->insn_opcode = MATCH_C_J;
+ INSERT_OPERAND(CIMM10, *insn, bimm);
+ }
+ else if(INSN_MATCHES(*insn, BEQ) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm_bits <= 5)
+ {
+ insn->insn_opcode = MATCH_C_BEQ;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm);
+ }
+ else if(INSN_MATCHES(*insn, BNE) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm_bits <= 5)
+ {
+ insn->insn_opcode = MATCH_C_BNE;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm);
+ }
+ else if(INSN_MATCHES(*insn, LD) && rs1 == 30 && imm%8 == 0 && imm_bits <= 9)
+ {
+ insn->insn_opcode = MATCH_C_LDSP;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm/8);
+ }
+ else if(INSN_MATCHES(*insn, LW) && rs1 == 30 && imm%4 == 0 && imm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_LWSP;
+ INSERT_OPERAND(CRD, *insn, rd);
+ INSERT_OPERAND(CIMM6, *insn, imm/4);
+ }
+ else if(INSN_MATCHES(*insn, SD) && rs1 == 30 && bimm%8 == 0 && bimm_bits <= 9)
+ {
+ insn->insn_opcode = MATCH_C_SDSP;
+ INSERT_OPERAND(CRS2, *insn, rs2);
+ INSERT_OPERAND(CIMM6, *insn, bimm/8);
+ }
+ else if(INSN_MATCHES(*insn, SW) && rs1 == 30 && bimm%4 == 0 && bimm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_SWSP;
+ INSERT_OPERAND(CRS2, *insn, rs2);
+ INSERT_OPERAND(CIMM6, *insn, bimm/4);
+ }
+ else if(INSN_MATCHES(*insn, LD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%8 == 0 && imm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_LD;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, imm/8);
+ }
+ else if(INSN_MATCHES(*insn, LW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%4 == 0 && imm_bits <= 7)
+ {
+ insn->insn_opcode = MATCH_C_LW;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, imm/4);
+ }
+ else if(INSN_MATCHES(*insn, SD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%8 == 0 && bimm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_SD;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm/8);
+ }
+ else if(INSN_MATCHES(*insn, SW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%4 == 0 && bimm_bits <= 7)
+ {
+ insn->insn_opcode = MATCH_C_SW;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm/4);
+ }
+ else if(INSN_MATCHES(*insn, LD) && imm == 0)
+ {
+ insn->insn_opcode = MATCH_C_LD0;
+ INSERT_OPERAND(CRS1, *insn, rs1);
+ INSERT_OPERAND(CRD, *insn, rd);
+ }
+ else if(INSN_MATCHES(*insn, LW) && imm == 0)
+ {
+ insn->insn_opcode = MATCH_C_LW0;
+ INSERT_OPERAND(CRS1, *insn, rs1);
+ INSERT_OPERAND(CRD, *insn, rd);
+ }
+ else if(INSN_MATCHES(*insn, FLD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%8 == 0 && imm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_FLD;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, imm/8);
+ }
+ else if(INSN_MATCHES(*insn, FLW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%4 == 0 && imm_bits <= 7)
+ {
+ insn->insn_opcode = MATCH_C_FLW;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd));
+ INSERT_OPERAND(CIMM5, *insn, imm/4);
+ }
+ else if(INSN_MATCHES(*insn, FSD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%8 == 0 && bimm_bits <= 8)
+ {
+ insn->insn_opcode = MATCH_C_FSD;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm/8);
+ }
+ else if(INSN_MATCHES(*insn, FSW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%4 == 0 && bimm_bits <= 7)
+ {
+ insn->insn_opcode = MATCH_C_FSW;
+ INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1));
+ INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2));
+ INSERT_OPERAND(CIMM5, *insn, bimm/4);
+ }
+ else
+ return 0;
+
+ gas_assert(insn_length(insn) == 2);
+
+ return 1;
+}
+#endif
+
+/* Initialise INSN from opcode entry MO. Leave its position unspecified. */
+
+static void
+create_insn (struct mips_cl_insn *insn, const struct riscv_opcode *mo)
+{
+ insn->insn_mo = mo;
+ insn->insn_opcode = mo->match;
+ insn->frag = NULL;
+ insn->where = 0;
+ insn->fixp = NULL;
+}
+
+/* Install INSN at the location specified by its "frag" and "where" fields. */
+
+static void
+install_insn (const struct mips_cl_insn *insn)
+{
+ char *f = insn->frag->fr_literal + insn->where;
+ md_number_to_chars (f, insn->insn_opcode, insn_length(insn));
+}
+
+/* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly
+ and install the opcode in the new location. */
+
+static void
+move_insn (struct mips_cl_insn *insn, fragS *frag, long where)
+{
+ insn->frag = frag;
+ insn->where = where;
+ if (insn->fixp != NULL)
+ {
+ insn->fixp->fx_frag = frag;
+ insn->fixp->fx_where = where;
+ }
+ install_insn (insn);
+}
+
+/* Add INSN to the end of the output. */
+
+static void
+add_fixed_insn (struct mips_cl_insn *insn)
+{
+ char *f = frag_more (insn_length (insn));
+ move_insn (insn, frag_now, f - frag_now->fr_literal);
+}
+
+static void
+add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var,
+ relax_substateT subtype, symbolS *symbol, offsetT offset)
+{
+ frag_grow (max_chars);
+ move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal);
+ frag_var (rs_machine_dependent, max_chars, var,
+ subtype, symbol, offset, NULL);
+}
+
+struct regname {
+ const char *name;
+ unsigned int num;
+};
+
+#define RNUM_MASK 0x000fff
+#define RTYPE_NUM 0x001000
+#define RTYPE_FPU 0x002000
+#define RTYPE_VEC 0x004000
+#define RTYPE_GP 0x008000
+#define RTYPE_CP0 0x010000
+#define RTYPE_VGR_REG 0x020000
+#define RTYPE_VFP_REG 0x040000
+
+#define X_REGISTER_NUMBERS \
+ {"x0", RTYPE_NUM | 0}, \
+ {"x1", RTYPE_NUM | 1}, \
+ {"x2", RTYPE_NUM | 2}, \
+ {"x3", RTYPE_NUM | 3}, \
+ {"x4", RTYPE_NUM | 4}, \
+ {"x5", RTYPE_NUM | 5}, \
+ {"x6", RTYPE_NUM | 6}, \
+ {"x7", RTYPE_NUM | 7}, \
+ {"x8", RTYPE_NUM | 8}, \
+ {"x9", RTYPE_NUM | 9}, \
+ {"x10", RTYPE_NUM | 10}, \
+ {"x11", RTYPE_NUM | 11}, \
+ {"x12", RTYPE_NUM | 12}, \
+ {"x13", RTYPE_NUM | 13}, \
+ {"x14", RTYPE_NUM | 14}, \
+ {"x15", RTYPE_NUM | 15}, \
+ {"x16", RTYPE_NUM | 16}, \
+ {"x17", RTYPE_NUM | 17}, \
+ {"x18", RTYPE_NUM | 18}, \
+ {"x19", RTYPE_NUM | 19}, \
+ {"x20", RTYPE_NUM | 20}, \
+ {"x21", RTYPE_NUM | 21}, \
+ {"x22", RTYPE_NUM | 22}, \
+ {"x23", RTYPE_NUM | 23}, \
+ {"x24", RTYPE_NUM | 24}, \
+ {"x25", RTYPE_NUM | 25}, \
+ {"x26", RTYPE_NUM | 26}, \
+ {"x27", RTYPE_NUM | 27}, \
+ {"x28", RTYPE_NUM | 28}, \
+ {"x29", RTYPE_NUM | 29}, \
+ {"x30", RTYPE_NUM | 30}, \
+ {"x31", RTYPE_NUM | 31}
+
+#define F_REGISTER_NUMBERS \
+ {"f0", RTYPE_FPU | 0}, \
+ {"f1", RTYPE_FPU | 1}, \
+ {"f2", RTYPE_FPU | 2}, \
+ {"f3", RTYPE_FPU | 3}, \
+ {"f4", RTYPE_FPU | 4}, \
+ {"f5", RTYPE_FPU | 5}, \
+ {"f6", RTYPE_FPU | 6}, \
+ {"f7", RTYPE_FPU | 7}, \
+ {"f8", RTYPE_FPU | 8}, \
+ {"f9", RTYPE_FPU | 9}, \
+ {"f10", RTYPE_FPU | 10}, \
+ {"f11", RTYPE_FPU | 11}, \
+ {"f12", RTYPE_FPU | 12}, \
+ {"f13", RTYPE_FPU | 13}, \
+ {"f14", RTYPE_FPU | 14}, \
+ {"f15", RTYPE_FPU | 15}, \
+ {"f16", RTYPE_FPU | 16}, \
+ {"f17", RTYPE_FPU | 17}, \
+ {"f18", RTYPE_FPU | 18}, \
+ {"f19", RTYPE_FPU | 19}, \
+ {"f20", RTYPE_FPU | 20}, \
+ {"f21", RTYPE_FPU | 21}, \
+ {"f22", RTYPE_FPU | 22}, \
+ {"f23", RTYPE_FPU | 23}, \
+ {"f24", RTYPE_FPU | 24}, \
+ {"f25", RTYPE_FPU | 25}, \
+ {"f26", RTYPE_FPU | 26}, \
+ {"f27", RTYPE_FPU | 27}, \
+ {"f28", RTYPE_FPU | 28}, \
+ {"f29", RTYPE_FPU | 29}, \
+ {"f30", RTYPE_FPU | 30}, \
+ {"f31", RTYPE_FPU | 31}
+
+/* Remaining symbolic register names */
+#define X_REGISTER_NAMES \
+ { "zero", 0 | RTYPE_GP }, \
+ { "ra", 1 | RTYPE_GP }, \
+ { "s0", 2 | RTYPE_GP }, \
+ { "s1", 3 | RTYPE_GP }, \
+ { "s2", 4 | RTYPE_GP }, \
+ { "s3", 5 | RTYPE_GP }, \
+ { "s4", 6 | RTYPE_GP }, \
+ { "s5", 7 | RTYPE_GP }, \
+ { "s6", 8 | RTYPE_GP }, \
+ { "s7", 9 | RTYPE_GP }, \
+ { "s8", 10 | RTYPE_GP }, \
+ { "s9", 11 | RTYPE_GP }, \
+ { "s10", 12 | RTYPE_GP }, \
+ { "s11", 13 | RTYPE_GP }, \
+ { "sp", 14 | RTYPE_GP }, \
+ { "tp", 15 | RTYPE_GP }, \
+ { "v0", 16 | RTYPE_GP }, \
+ { "v1", 17 | RTYPE_GP }, \
+ { "a0", 18 | RTYPE_GP }, \
+ { "a1", 19 | RTYPE_GP }, \
+ { "a2", 20 | RTYPE_GP }, \
+ { "a3", 21 | RTYPE_GP }, \
+ { "a4", 22 | RTYPE_GP }, \
+ { "a5", 23 | RTYPE_GP }, \
+ { "a6", 24 | RTYPE_GP }, \
+ { "a7", 25 | RTYPE_GP }, \
+ { "t0", 26 | RTYPE_GP }, \
+ { "t1", 27 | RTYPE_GP }, \
+ { "t2", 28 | RTYPE_GP }, \
+ { "t3", 29 | RTYPE_GP }, \
+ { "t4", 30 | RTYPE_GP }, \
+ { "gp", 31 | RTYPE_GP }
+
+#define F_REGISTER_NAMES \
+ { "fs0", 0 | RTYPE_FPU }, \
+ { "fs1", 1 | RTYPE_FPU }, \
+ { "fs2", 2 | RTYPE_FPU }, \
+ { "fs3", 3 | RTYPE_FPU }, \
+ { "fs4", 4 | RTYPE_FPU }, \
+ { "fs5", 5 | RTYPE_FPU }, \
+ { "fs6", 6 | RTYPE_FPU }, \
+ { "fs7", 7 | RTYPE_FPU }, \
+ { "fs8", 8 | RTYPE_FPU }, \
+ { "fs9", 9 | RTYPE_FPU }, \
+ { "fs10", 10 | RTYPE_FPU }, \
+ { "fs11", 11 | RTYPE_FPU }, \
+ { "fs12", 12 | RTYPE_FPU }, \
+ { "fs13", 13 | RTYPE_FPU }, \
+ { "fs14", 14 | RTYPE_FPU }, \
+ { "fs15", 15 | RTYPE_FPU }, \
+ { "fv0", 16 | RTYPE_FPU }, \
+ { "fv1", 17 | RTYPE_FPU }, \
+ { "fa0", 18 | RTYPE_FPU }, \
+ { "fa1", 19 | RTYPE_FPU }, \
+ { "fa2", 20 | RTYPE_FPU }, \
+ { "fa3", 21 | RTYPE_FPU }, \
+ { "fa4", 22 | RTYPE_FPU }, \
+ { "fa5", 23 | RTYPE_FPU }, \
+ { "fa6", 24 | RTYPE_FPU }, \
+ { "fa7", 25 | RTYPE_FPU }, \
+ { "ft0", 26 | RTYPE_FPU }, \
+ { "ft1", 27 | RTYPE_FPU }, \
+ { "ft2", 28 | RTYPE_FPU }, \
+ { "ft3", 29 | RTYPE_FPU }, \
+ { "ft4", 30 | RTYPE_FPU }, \
+ { "ft5", 31 | RTYPE_FPU }
+
+#define RISCV_VEC_GR_REGISTER_NAMES \
+ {"vx0", RTYPE_VGR_REG | 0}, \
+ {"vx1", RTYPE_VGR_REG | 1}, \
+ {"vx2", RTYPE_VGR_REG | 2}, \
+ {"vx3", RTYPE_VGR_REG | 3}, \
+ {"vx4", RTYPE_VGR_REG | 4}, \
+ {"vx5", RTYPE_VGR_REG | 5}, \
+ {"vx6", RTYPE_VGR_REG | 6}, \
+ {"vx7", RTYPE_VGR_REG | 7}, \
+ {"vx8", RTYPE_VGR_REG | 8}, \
+ {"vx9", RTYPE_VGR_REG | 9}, \
+ {"vx10", RTYPE_VGR_REG | 10}, \
+ {"vx11", RTYPE_VGR_REG | 11}, \
+ {"vx12", RTYPE_VGR_REG | 12}, \
+ {"vx13", RTYPE_VGR_REG | 13}, \
+ {"vx14", RTYPE_VGR_REG | 14}, \
+ {"vx15", RTYPE_VGR_REG | 15}, \
+ {"vx16", RTYPE_VGR_REG | 16}, \
+ {"vx17", RTYPE_VGR_REG | 17}, \
+ {"vx18", RTYPE_VGR_REG | 18}, \
+ {"vx19", RTYPE_VGR_REG | 19}, \
+ {"vx20", RTYPE_VGR_REG | 20}, \
+ {"vx21", RTYPE_VGR_REG | 21}, \
+ {"vx22", RTYPE_VGR_REG | 22}, \
+ {"vx23", RTYPE_VGR_REG | 23}, \
+ {"vx24", RTYPE_VGR_REG | 24}, \
+ {"vx25", RTYPE_VGR_REG | 25}, \
+ {"vx26", RTYPE_VGR_REG | 26}, \
+ {"vx27", RTYPE_VGR_REG | 27}, \
+ {"vx28", RTYPE_VGR_REG | 28}, \
+ {"vx29", RTYPE_VGR_REG | 29}, \
+ {"vx30", RTYPE_VGR_REG | 30}, \
+ {"vx31", RTYPE_VGR_REG | 31}
+
+#define RISCV_VEC_GR_SYMBOLIC_REGISTER_NAMES \
+ {"vzero", RTYPE_VGR_REG | 0}, \
+ {"vra", RTYPE_VGR_REG | 1}, \
+ {"vs0", RTYPE_VGR_REG | 2}, \
+ {"vs1", RTYPE_VGR_REG | 3}, \
+ {"vs2", RTYPE_VGR_REG | 4}, \
+ {"vs3", RTYPE_VGR_REG | 5}, \
+ {"vs4", RTYPE_VGR_REG | 6}, \
+ {"vs5", RTYPE_VGR_REG | 7}, \
+ {"vs6", RTYPE_VGR_REG | 8}, \
+ {"vs7", RTYPE_VGR_REG | 9}, \
+ {"vs8", RTYPE_VGR_REG | 10}, \
+ {"vs9", RTYPE_VGR_REG | 11}, \
+ {"vs10", RTYPE_VGR_REG | 12}, \
+ {"vs11", RTYPE_VGR_REG | 13}, \
+ {"vsp", RTYPE_VGR_REG | 14}, \
+ {"vtp", RTYPE_VGR_REG | 15}, \
+ {"vv0", RTYPE_VGR_REG | 16}, \
+ {"vv1", RTYPE_VGR_REG | 17}, \
+ {"va0", RTYPE_VGR_REG | 18}, \
+ {"va1", RTYPE_VGR_REG | 19}, \
+ {"va2", RTYPE_VGR_REG | 20}, \
+ {"va3", RTYPE_VGR_REG | 21}, \
+ {"va4", RTYPE_VGR_REG | 22}, \
+ {"va5", RTYPE_VGR_REG | 23}, \
+ {"va6", RTYPE_VGR_REG | 24}, \
+ {"va7", RTYPE_VGR_REG | 25}, \
+ {"vt0", RTYPE_VGR_REG | 26}, \
+ {"vt1", RTYPE_VGR_REG | 27}, \
+ {"vt2", RTYPE_VGR_REG | 28}, \
+ {"vt3", RTYPE_VGR_REG | 29}, \
+ {"vt4", RTYPE_VGR_REG | 30}, \
+ {"vgp", RTYPE_VGR_REG | 31}
+
+#define RISCV_VEC_FP_REGISTER_NAMES \
+ {"vf0", RTYPE_VFP_REG | 0}, \
+ {"vf1", RTYPE_VFP_REG | 1}, \
+ {"vf2", RTYPE_VFP_REG | 2}, \
+ {"vf3", RTYPE_VFP_REG | 3}, \
+ {"vf4", RTYPE_VFP_REG | 4}, \
+ {"vf5", RTYPE_VFP_REG | 5}, \
+ {"vf6", RTYPE_VFP_REG | 6}, \
+ {"vf7", RTYPE_VFP_REG | 7}, \
+ {"vf8", RTYPE_VFP_REG | 8}, \
+ {"vf9", RTYPE_VFP_REG | 9}, \
+ {"vf10", RTYPE_VFP_REG | 10}, \
+ {"vf11", RTYPE_VFP_REG | 11}, \
+ {"vf12", RTYPE_VFP_REG | 12}, \
+ {"vf13", RTYPE_VFP_REG | 13}, \
+ {"vf14", RTYPE_VFP_REG | 14}, \
+ {"vf15", RTYPE_VFP_REG | 15}, \
+ {"vf16", RTYPE_VFP_REG | 16}, \
+ {"vf17", RTYPE_VFP_REG | 17}, \
+ {"vf18", RTYPE_VFP_REG | 18}, \
+ {"vf19", RTYPE_VFP_REG | 19}, \
+ {"vf20", RTYPE_VFP_REG | 20}, \
+ {"vf21", RTYPE_VFP_REG | 21}, \
+ {"vf22", RTYPE_VFP_REG | 22}, \
+ {"vf23", RTYPE_VFP_REG | 23}, \
+ {"vf24", RTYPE_VFP_REG | 24}, \
+ {"vf25", RTYPE_VFP_REG | 25}, \
+ {"vf26", RTYPE_VFP_REG | 26}, \
+ {"vf27", RTYPE_VFP_REG | 27}, \
+ {"vf28", RTYPE_VFP_REG | 28}, \
+ {"vf29", RTYPE_VFP_REG | 29}, \
+ {"vf30", RTYPE_VFP_REG | 30}, \
+ {"vf31", RTYPE_VFP_REG | 31}
+
+static const struct regname reg_names[] = {
+ X_REGISTER_NUMBERS,
+ X_REGISTER_NAMES,
+
+ F_REGISTER_NUMBERS,
+ F_REGISTER_NAMES,
+
+#define DECLARE_CSR(name, num) {#name, RTYPE_CP0 | num},
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+
+ RISCV_VEC_GR_REGISTER_NAMES,
+ RISCV_VEC_FP_REGISTER_NAMES,
+ RISCV_VEC_GR_SYMBOLIC_REGISTER_NAMES,
+
+ {0, 0}
+};
+
+static struct hash_control *reg_names_hash = NULL;
+
+static int
+reg_lookup (char **s, unsigned int types, unsigned int *regnop)
+{
+ struct regname *r;
+ char *e;
+ char save_c;
+ int reg = -1;
+
+ /* Find end of name. */
+ e = *s;
+ if (is_name_beginner (*e))
+ ++e;
+ while (is_part_of_name (*e))
+ ++e;
+
+ /* Terminate name. */
+ save_c = *e;
+ *e = '\0';
+
+ /* Look for the register. */
+ r = (struct regname *) hash_find (reg_names_hash, *s);
+ if (r != NULL && (r->num & types))
+ reg = r->num & RNUM_MASK;
+
+ /* Advance to next token if a register was recognised. */
+ if (reg >= 0)
+ *s = e;
+
+ *e = save_c;
+ if (regnop)
+ *regnop = reg;
+ return reg >= 0;
+}
+
+static unsigned int
+reg_lookup_assert (const char *s, unsigned int types)
+{
+ struct regname *r = (struct regname *) hash_find (reg_names_hash, s);
+ gas_assert (r != NULL && (r->num & types));
+ return r->num & RNUM_MASK;
+}
+
+static int
+arg_lookup(char **s, const char* const* array, size_t size, unsigned *regnop)
+{
+ const char *p = strchr(*s, ',');
+ size_t i, len = p ? (size_t)(p - *s) : strlen(*s);
+
+ for (i = 0; i < size; i++)
+ if (array[i] != NULL && strncmp(array[i], *s, len) == 0)
+ {
+ *regnop = i;
+ *s += len;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This function is called once, at assembler startup time. It should set up
+ all the tables, etc. that the MD part of the assembler will need. */
+
+void
+md_begin (void)
+{
+ const char *retval = NULL;
+ int i = 0;
+
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, 0))
+ as_warn (_("Could not set architecture and machine"));
+
+ op_hash = hash_new ();
+
+ for (i = 0; i < NUMOPCODES;)
+ {
+ const char *name = riscv_opcodes[i].name;
+
+ if (riscv_subset_supports(riscv_opcodes[i].subset))
+ retval = hash_insert (op_hash, name, (void *) &riscv_opcodes[i]);
+
+ if (retval != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ riscv_opcodes[i].name, retval);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+ do
+ {
+ if (riscv_opcodes[i].pinfo != INSN_MACRO)
+ {
+ if (!validate_mips_insn (&riscv_opcodes[i]))
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+ ++i;
+ }
+ while ((i < NUMOPCODES) && !strcmp (riscv_opcodes[i].name, name));
+ }
+
+ reg_names_hash = hash_new ();
+ for (i = 0; reg_names[i].name; i++)
+ {
+ retval = hash_insert (reg_names_hash, reg_names[i].name,
+ (void*) &reg_names[i]);
+ if (retval != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ reg_names[i].name, retval);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+ }
+
+ mips_clear_insn_labels ();
+
+ /* set the default alignment for the text section (2**2) */
+ record_alignment (text_section, 2);
+}
+
+void
+md_assemble (char *str)
+{
+ struct mips_cl_insn insn;
+
+ imm_expr.X_op = O_absent;
+ offset_expr.X_op = O_absent;
+ imm_reloc = BFD_RELOC_UNUSED;
+ offset_reloc = BFD_RELOC_UNUSED;
+
+ mips_ip (str, &insn);
+ DBG ((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"),
+ str, insn.insn_opcode));
+
+
+ if (insn_error)
+ {
+ as_bad ("%s `%s'", insn_error, str);
+ return;
+ }
+
+ if (insn.insn_mo->pinfo == INSN_MACRO)
+ macro (&insn);
+ else
+ {
+ if (imm_expr.X_op != O_absent)
+ append_insn (&insn, &imm_expr, imm_reloc);
+ else if (offset_expr.X_op != O_absent)
+ append_insn (&insn, &offset_expr, offset_reloc);
+ else
+ append_insn (&insn, NULL, BFD_RELOC_UNUSED);
+ }
+}
+
+/* Output an instruction. IP is the instruction information.
+ ADDRESS_EXPR is an operand of the instruction to be used with
+ RELOC_TYPE. */
+
+static void
+append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
+ bfd_reloc_code_real_type reloc_type)
+{
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (0);
+#endif
+
+ gas_assert(reloc_type <= BFD_RELOC_UNUSED);
+
+#if 0
+ /* don't compress instructions with relocs */
+ int compressible = (reloc_type == BFD_RELOC_UNUSED ||
+ address_expr == NULL || address_expr->X_op == O_constant) && mips_opts.rvc;
+
+ /* speculate that branches/jumps can be compressed. if not, we'll relax. */
+ if (address_expr != NULL && mips_opts.rvc)
+ {
+ int compressible_branch = reloc_type == BFD_RELOC_12_PCREL &&
+ (INSN_MATCHES(*ip, BEQ) || INSN_MATCHES(*ip, BNE));
+ int compressible_jump = reloc_type == BFD_RELOC_MIPS_JMP &&
+ INSN_MATCHES(*ip, JAL);
+ if(compressible_branch || compressible_jump)
+ {
+ if(riscv_rvc_compress(ip))
+ {
+ add_relaxed_insn(ip, 4 /* worst case length */, 0,
+ RELAX_BRANCH_ENCODE(compressible_jump, 0),
+ address_expr->X_add_symbol,
+ address_expr->X_add_number);
+ reloc_type = BFD_RELOC_UNUSED;
+ return;
+ }
+ }
+ }
+#endif
+
+ if (address_expr != NULL)
+ {
+ if (address_expr->X_op == O_constant)
+ {
+ switch (reloc_type)
+ {
+ case BFD_RELOC_32:
+ ip->insn_opcode |= address_expr->X_add_number;
+ break;
+
+ case BFD_RELOC_RISCV_HI20:
+ ip->insn_opcode |= ENCODE_UTYPE_IMM (
+ RISCV_LUI_HIGH_PART (address_expr->X_add_number));
+ break;
+
+ case BFD_RELOC_RISCV_LO12_S:
+ ip->insn_opcode |= ENCODE_STYPE_IMM (address_expr->X_add_number);
+ break;
+
+ case BFD_RELOC_UNUSED:
+ case BFD_RELOC_RISCV_LO12_I:
+ ip->insn_opcode |= ENCODE_ITYPE_IMM (address_expr->X_add_number);
+ break;
+
+ default:
+ internalError ();
+ }
+ reloc_type = BFD_RELOC_UNUSED;
+ }
+ else if (reloc_type == BFD_RELOC_12_PCREL)
+ {
+ add_relaxed_insn (ip, relaxed_branch_length (NULL, NULL, 0), 4,
+ RELAX_BRANCH_ENCODE (0, 0, 0),
+ address_expr->X_add_symbol,
+ address_expr->X_add_number);
+ return;
+ }
+ else if (reloc_type < BFD_RELOC_UNUSED)
+ {
+ reloc_howto_type *howto;
+
+ howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
+ if (howto == NULL)
+ as_bad (_("Unsupported MIPS relocation number %d"), reloc_type);
+
+ ip->fixp = fix_new_exp (ip->frag, ip->where,
+ bfd_get_reloc_size (howto),
+ address_expr,
+ reloc_type == BFD_RELOC_12_PCREL ||
+ reloc_type == BFD_RELOC_RISCV_CALL ||
+ reloc_type == BFD_RELOC_MIPS_JMP,
+ reloc_type);
+
+ /* These relocations can have an addend that won't fit in
+ 4 octets for 64bit assembly. */
+ if (rv64
+ && ! howto->partial_inplace
+ && (reloc_type == BFD_RELOC_32
+ || reloc_type == BFD_RELOC_64
+ || reloc_type == BFD_RELOC_CTOR
+ || reloc_type == BFD_RELOC_RISCV_HI20
+ || reloc_type == BFD_RELOC_RISCV_LO12_I
+ || reloc_type == BFD_RELOC_RISCV_LO12_S))
+ ip->fixp->fx_no_overflow = 1;
+ }
+ }
+
+#if 0
+ if (compressible)
+ riscv_rvc_compress(ip);
+#endif
+ add_fixed_insn (ip);
+
+ install_insn (ip);
+
+ /* We just output an insn, so the next one doesn't have a label. */
+ mips_clear_insn_labels ();
+}
+
+/* Build an instruction created by a macro expansion. This is passed
+ a pointer to the count of instructions created so far, an
+ expression, the name of the instruction to build, an operand format
+ string, and corresponding arguments. */
+
+static void
+macro_build (expressionS *ep, const char *name, const char *fmt, ...)
+{
+ const struct riscv_opcode *mo;
+ struct mips_cl_insn insn;
+ bfd_reloc_code_real_type r;
+ va_list args;
+
+ va_start (args, fmt);
+
+ r = BFD_RELOC_UNUSED;
+ mo = (struct riscv_opcode *) hash_find (op_hash, name);
+ gas_assert (mo);
+ gas_assert (strcmp (name, mo->name) == 0);
+
+ create_insn (&insn, mo);
+ for (;;)
+ {
+ switch (*fmt++)
+ {
+ case 'd':
+ INSERT_OPERAND (RD, insn, va_arg (args, int));
+ continue;
+
+ case 's':
+ INSERT_OPERAND (RS1, insn, va_arg (args, int));
+ continue;
+
+ case 't':
+ INSERT_OPERAND (RS2, insn, va_arg (args, int));
+ continue;
+
+ case '>':
+ INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
+ continue;
+
+ case 'j':
+ case 'u':
+ case 'q':
+ gas_assert (ep != NULL);
+ r = va_arg (args, int);
+ continue;
+
+ case '\0':
+ break;
+ case ',':
+ continue;
+ default:
+ internalError ();
+ }
+ break;
+ }
+ va_end (args);
+ gas_assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
+
+ append_insn (&insn, ep, r);
+}
+
+/*
+ * Sign-extend 32-bit mode constants that have bit 31 set and all
+ * higher bits unset.
+ */
+static void
+normalize_constant_expr (expressionS *ex)
+{
+ if (rv64)
+ return;
+ if (ex->X_op == O_constant
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/*
+ * Sign-extend 32-bit mode address offsets that have bit 31 set and
+ * all higher bits unset.
+ */
+static void
+normalize_address_expr (expressionS *ex)
+{
+ if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
+ || (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
+ && IS_ZEXT_32BIT_NUM (ex->X_add_number))
+ ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
+ - 0x80000000);
+}
+
+/* Load an entry from the GOT. */
+static void
+pcrel_access (int destreg, int tempreg, expressionS *ep,
+ const char* lo_insn, const char* lo_pattern,
+ bfd_reloc_code_real_type hi_reloc,
+ bfd_reloc_code_real_type lo_reloc)
+{
+ macro_build (ep, "auipc", "d,u", tempreg, hi_reloc);
+ macro_build (ep, lo_insn, lo_pattern, destreg, tempreg, lo_reloc);
+}
+
+static void
+pcrel_load (int destreg, int tempreg, expressionS *ep, const char* lo_insn,
+ bfd_reloc_code_real_type hi_reloc,
+ bfd_reloc_code_real_type lo_reloc)
+{
+ pcrel_access (destreg, tempreg, ep, lo_insn, "d,s,j", hi_reloc, lo_reloc);
+}
+
+static void
+pcrel_store (int srcreg, int tempreg, expressionS *ep, const char* lo_insn,
+ bfd_reloc_code_real_type hi_reloc,
+ bfd_reloc_code_real_type lo_reloc)
+{
+ pcrel_access (srcreg, tempreg, ep, lo_insn, "t,s,q", hi_reloc, lo_reloc);
+}
+
+static void
+pcrel_vf (int tempreg, expressionS *ep,
+ bfd_reloc_code_real_type hi_reloc,
+ bfd_reloc_code_real_type lo_reloc)
+{
+ macro_build (ep, "auipc", "d,u", tempreg, hi_reloc);
+ macro_build (ep, "vf", "s,q", tempreg, lo_reloc);
+}
+
+/* PC-relative function call using AUIPC/JALR, relaxed to JAL. */
+static void
+riscv_call (int destreg, int tempreg, expressionS *ep,
+ bfd_reloc_code_real_type reloc)
+{
+ macro_build (ep, "auipc", "d,u", tempreg, reloc);
+ macro_build (NULL, "jalr", "d,s", destreg, tempreg);
+}
+
+/* Warn if an expression is not a constant. */
+
+static void
+check_absolute_expr (struct mips_cl_insn *ip, expressionS *ex)
+{
+ if (ex->X_op == O_big)
+ as_bad (_("unsupported large constant"));
+ else if (ex->X_op != O_constant)
+ as_bad (_("Instruction %s requires absolute expression"),
+ ip->insn_mo->name);
+ normalize_constant_expr (ex);
+}
+
+/* load_const generates an unoptimized instruction sequence to load
+ * an absolute expression into a register. */
+static void
+load_const (int reg, expressionS *ep)
+{
+ gas_assert (ep->X_op == O_constant);
+ gas_assert (reg != ZERO);
+
+ // this is an awful way to generate arbitrary 64-bit constants.
+ // fortunately, this is just used for hand-coded assembly programs.
+ if (rv64 && !IS_SEXT_32BIT_NUM(ep->X_add_number))
+ {
+ expressionS upper = *ep, lower = *ep;
+ upper.X_add_number = (int64_t)ep->X_add_number >> (RISCV_IMM_BITS-1);
+ load_const(reg, &upper);
+
+ macro_build (NULL, "slli", "d,s,>", reg, reg, RISCV_IMM_BITS-1);
+
+ lower.X_add_number = ep->X_add_number & (RISCV_IMM_REACH/2-1);
+ if (lower.X_add_number != 0)
+ macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_RISCV_LO12_I);
+ }
+ else // load a sign-extended 32-bit constant
+ {
+ int hi_reg = ZERO;
+
+ int32_t hi = ep->X_add_number & (RISCV_IMM_REACH-1);
+ hi = hi << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS);
+ hi = (int32_t)ep->X_add_number - hi;
+ if(hi)
+ {
+ macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20);
+ hi_reg = reg;
+ }
+
+ if((ep->X_add_number & (RISCV_IMM_REACH-1)) || hi_reg == ZERO)
+ macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg, BFD_RELOC_RISCV_LO12_I);
+ }
+}
+
+/*
+ * Build macros
+ * This routine implements the seemingly endless macro or synthesized
+ * instructions and addressing modes in the mips assembly language. Many
+ * of these macros are simple and are similar to each other. These could
+ * probably be handled by some kind of table or grammar approach instead of
+ * this verbose method. Others are not simple macros but are more like
+ * optimizing code generation.
+ * One interesting optimization is when several store macros appear
+ * consecutively that would load AT with the upper half of the same address.
+ * The ensuing load upper instructions are ommited. This implies some kind
+ * of global optimization. We currently only optimize within a single macro.
+ * For many of the load and store macros if the address is specified as a
+ * constant expression in the first 64k of memory (ie ld $2,0x4000c) we
+ * first load register 'at' with zero and use it as the base register. The
+ * mips assembler simply uses register $zero. Just one tiny optimization
+ * we're missing.
+ */
+static void
+macro (struct mips_cl_insn *ip)
+{
+ unsigned int rd, rs1, rs2;
+ int mask;
+
+ rd = (ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD;
+ rs1 = (ip->insn_opcode >> OP_SH_RS1) & OP_MASK_RS1;
+ rs2 = (ip->insn_opcode >> OP_SH_RS2) & OP_MASK_RS2;
+ mask = ip->insn_mo->mask;
+
+ switch (mask)
+ {
+ case M_LI:
+ load_const (rd, &imm_expr);
+ break;
+
+ case M_LA:
+ case M_LLA:
+ /* Load the address of a symbol into a register. */
+ if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+ as_bad(_("offset too large"));
+
+ if (offset_expr.X_op == O_constant)
+ load_const (rd, &offset_expr);
+ else if (is_pic && mask == M_LA) /* Global PIC symbol */
+ pcrel_load (rd, rd, &offset_expr, LOAD_ADDRESS_INSN,
+ BFD_RELOC_RISCV_GOT_HI20, BFD_RELOC_RISCV_GOT_LO12);
+ else /* Local PIC symbol, or any non-PIC symbol */
+ pcrel_load (rd, rd, &offset_expr, "addi",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LA_TLS_GD:
+ pcrel_load (rd, rd, &offset_expr, "addi",
+ BFD_RELOC_RISCV_TLS_GD_HI20, BFD_RELOC_RISCV_TLS_GD_LO12);
+ break;
+
+ case M_LA_TLS_IE:
+ pcrel_load (rd, rd, &offset_expr, LOAD_ADDRESS_INSN,
+ BFD_RELOC_RISCV_TLS_GOT_HI20, BFD_RELOC_RISCV_TLS_GOT_LO12);
+ break;
+
+ case M_LB:
+ pcrel_load (rd, rd, &offset_expr, "lb",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LBU:
+ pcrel_load (rd, rd, &offset_expr, "lbu",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LH:
+ pcrel_load (rd, rd, &offset_expr, "lh",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LHU:
+ pcrel_load (rd, rd, &offset_expr, "lhu",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LW:
+ pcrel_load (rd, rd, &offset_expr, "lw",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LWU:
+ pcrel_load (rd, rd, &offset_expr, "lwu",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_LD:
+ pcrel_load (rd, rd, &offset_expr, "ld",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_FLW:
+ pcrel_load (rd, rs1, &offset_expr, "flw",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_FLD:
+ pcrel_load (rd, rs1, &offset_expr, "fld",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_I);
+ break;
+
+ case M_SB:
+ pcrel_store (rs2, rs1, &offset_expr, "sb",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_SH:
+ pcrel_store (rs2, rs1, &offset_expr, "sh",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_SW:
+ pcrel_store (rs2, rs1, &offset_expr, "sw",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_SD:
+ pcrel_store (rs2, rs1, &offset_expr, "sd",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_FSW:
+ pcrel_store (rs2, rs1, &offset_expr, "fsw",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_FSD:
+ pcrel_store (rs2, rs1, &offset_expr, "fsd",
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_VF:
+ pcrel_vf (rs1, &offset_expr,
+ BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S);
+ break;
+
+ case M_JUMP:
+ rd = 0;
+ goto do_call;
+ case M_CALL:
+ rd = LINK_REG;
+do_call:
+ rs1 = reg_lookup_assert ("t0", RTYPE_GP);
+ riscv_call (rd, rs1, &offset_expr, offset_reloc);
+ break;
+
+ default:
+ as_bad (_("Macro %s not implemented"), ip->insn_mo->name);
+ break;
+ }
+}
+
+/* For consistency checking, verify that all bits are specified either
+ by the match/mask part of the instruction definition, or by the
+ operand list. */
+static int
+validate_mips_insn (const struct riscv_opcode *opc)
+{
+ const char *p = opc->args;
+ char c;
+ insn_t required_bits, used_bits = opc->mask;
+
+ if ((used_bits & opc->match) != opc->match)
+ {
+ as_bad (_("internal: bad mips opcode (mask error): %s %s"),
+ opc->name, opc->args);
+ return 0;
+ }
+ required_bits = ((insn_t)1 << (8 * riscv_insn_length (opc->match))) - 1;
+
+#define USE_BITS(mask,shift) (used_bits |= ((insn_t)(mask) << (shift)))
+ while (*p)
+ switch (c = *p++)
+ {
+ /* Xcustom */
+ case '^':
+ switch (c = *p++)
+ {
+ case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
+ case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
+ case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break;
+ case 'j': USE_BITS (OP_MASK_CUSTOM_IMM, OP_SH_CUSTOM_IMM); break;
+ }
+ break;
+ /* Xhwacha */
+ case '#':
+ switch (c = *p++)
+ {
+ case 'g': USE_BITS (OP_MASK_IMMNGPR, OP_SH_IMMNGPR); break;
+ case 'f': USE_BITS (OP_MASK_IMMNFPR, OP_SH_IMMNFPR); break;
+ case 'n': USE_BITS (OP_MASK_IMMSEGNELM, OP_SH_IMMSEGNELM); break;
+ case 'd': USE_BITS (OP_MASK_VRD, OP_SH_VRD); break;
+ case 's': USE_BITS (OP_MASK_VRS, OP_SH_VRS); break;
+ case 't': USE_BITS (OP_MASK_VRT, OP_SH_VRT); break;
+ case 'r': USE_BITS (OP_MASK_VRR, OP_SH_VRR); break;
+ case 'D': USE_BITS (OP_MASK_VFD, OP_SH_VFD); break;
+ case 'S': USE_BITS (OP_MASK_VFS, OP_SH_VFS); break;
+ case 'T': USE_BITS (OP_MASK_VFT, OP_SH_VFT); break;
+ case 'R': USE_BITS (OP_MASK_VFR, OP_SH_VFR); break;
+
+ default:
+ as_bad (_("internal: bad mips opcode (unknown extension operand type `#%c'): %s %s"),
+ c, opc->name, opc->args);
+ return 0;
+ }
+ break;
+ case ',': break;
+ case '(': break;
+ case ')': break;
+ case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
+ case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
+ case 'A': break;
+ case 'D': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
+ case 'Z': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
+ case 'E': USE_BITS (OP_MASK_CSR, OP_SH_CSR); break;
+ case 'I': break;
+ case 'R': USE_BITS (OP_MASK_RS3, OP_SH_RS3); break;
+ case 'S': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
+ case 'U': USE_BITS (OP_MASK_RS1, OP_SH_RS1); /* fallthru */
+ case 'T': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break;
+ case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
+ case 'm': USE_BITS (OP_MASK_RM, OP_SH_RM); break;
+ case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
+ case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break;
+ case 'P': USE_BITS (OP_MASK_PRED, OP_SH_PRED); break;
+ case 'Q': USE_BITS (OP_MASK_SUCC, OP_SH_SUCC); break;
+ case 'o':
+ case 'j': used_bits |= ENCODE_ITYPE_IMM(-1U); break;
+ case 'a': used_bits |= ENCODE_UJTYPE_IMM(-1U); break;
+ case 'p': used_bits |= ENCODE_SBTYPE_IMM(-1U); break;
+ case 'q': used_bits |= ENCODE_STYPE_IMM(-1U); break;
+ case 'u': used_bits |= ENCODE_UTYPE_IMM(-1U); break;
+ case '[': break;
+ case ']': break;
+ case '0': break;
+ default:
+ as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
+ c, opc->name, opc->args);
+ return 0;
+ }
+#undef USE_BITS
+ if (used_bits != required_bits)
+ {
+ as_bad (_("internal: bad mips opcode (bits 0x%lx undefined): %s %s"),
+ ~(long)(used_bits & required_bits), opc->name, opc->args);
+ return 0;
+ }
+ return 1;
+}
+
+struct percent_op_match
+{
+ const char *str;
+ bfd_reloc_code_real_type reloc;
+};
+
+static const struct percent_op_match percent_op_utype[] =
+{
+ {"%tprel_hi", BFD_RELOC_RISCV_TPREL_HI20},
+ {"%tls_ie_hi", BFD_RELOC_RISCV_TLS_IE_HI20},
+ {"%hi", BFD_RELOC_RISCV_HI20},
+ {0, 0}
+};
+
+static const struct percent_op_match percent_op_itype[] =
+{
+ {"%lo", BFD_RELOC_RISCV_LO12_I},
+ {"%tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_I},
+ {"%tls_ie_lo", BFD_RELOC_RISCV_TLS_IE_LO12},
+ {"%tls_ie_off", BFD_RELOC_RISCV_TLS_IE_LO12_I},
+ {0, 0}
+};
+
+static const struct percent_op_match percent_op_stype[] =
+{
+ {"%lo", BFD_RELOC_RISCV_LO12_S},
+ {"%tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_S},
+ {"%tls_ie_off", BFD_RELOC_RISCV_TLS_IE_LO12_S},
+ {0, 0}
+};
+
+static const struct percent_op_match percent_op_rtype[] =
+{
+ {"%tprel_add", BFD_RELOC_RISCV_TPREL_ADD},
+ {"%tls_ie_add", BFD_RELOC_RISCV_TLS_IE_ADD},
+ {0, 0}
+};
+
+/* Return true if *STR points to a relocation operator. When returning true,
+ move *STR over the operator and store its relocation code in *RELOC.
+ Leave both *STR and *RELOC alone when returning false. */
+
+static bfd_boolean
+parse_relocation (char **str, bfd_reloc_code_real_type *reloc,
+ const struct percent_op_match *percent_op)
+{
+ for ( ; percent_op->str; percent_op++)
+ if (strncasecmp (*str, percent_op->str, strlen (percent_op->str)) == 0)
+ {
+ int len = strlen (percent_op->str);
+
+ if (!ISSPACE ((*str)[len]) && (*str)[len] != '(')
+ continue;
+
+ *str += strlen (percent_op->str);
+ *reloc = percent_op->reloc;
+
+ /* Check whether the output BFD supports this relocation.
+ If not, issue an error and fall back on something safe. */
+ if (!bfd_reloc_type_lookup (stdoutput, percent_op->reloc))
+ {
+ as_bad ("relocation %s isn't supported by the current ABI",
+ percent_op->str);
+ *reloc = BFD_RELOC_UNUSED;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/* Parse string STR as a 16-bit relocatable operand. Store the
+ expression in *EP and the relocation, if any, in RELOC.
+ Return the number of relocation operators used (0 or 1).
+
+ On exit, EXPR_END points to the first character after the expression. */
+
+static size_t
+my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
+ char *str, const struct percent_op_match *percent_op)
+{
+ size_t reloc_index;
+ int crux_depth, str_depth;
+ char *crux;
+
+ /* Search for the start of the main expression.
+ End the loop with CRUX pointing to the start
+ of the main expression and with CRUX_DEPTH containing the number
+ of open brackets at that point. */
+ reloc_index = -1;
+ str_depth = 0;
+ do
+ {
+ reloc_index++;
+ crux = str;
+ crux_depth = str_depth;
+
+ /* Skip over whitespace and brackets, keeping count of the number
+ of brackets. */
+ while (*str == ' ' || *str == '\t' || *str == '(')
+ if (*str++ == '(')
+ str_depth++;
+ }
+ while (*str == '%'
+ && reloc_index < 1
+ && parse_relocation (&str, reloc, percent_op));
+
+ my_getExpression (ep, crux);
+ str = expr_end;
+
+ /* Match every open bracket. */
+ while (crux_depth > 0 && (*str == ')' || *str == ' ' || *str == '\t'))
+ if (*str++ == ')')
+ crux_depth--;
+
+ if (crux_depth > 0)
+ as_bad ("unclosed '('");
+
+ expr_end = str;
+
+ return reloc_index;
+}
+
+/* This routine assembles an instruction into its binary format. As a
+ side effect, it sets one of the global variables imm_reloc or
+ offset_reloc to the type of relocation to do if one of the operands
+ is an address expression. */
+
+static void
+mips_ip (char *str, struct mips_cl_insn *ip)
+{
+ char *s;
+ const char *args;
+ char c = 0;
+ struct riscv_opcode *insn;
+ char *argsStart;
+ unsigned int regno;
+ char save_c = 0;
+ int argnum;
+ unsigned int rtype;
+ const struct percent_op_match *p;
+
+ insn_error = NULL;
+
+ /* If the instruction contains a '.', we first try to match an instruction
+ including the '.'. Then we try again without the '.'. */
+ insn = NULL;
+ for (s = str; *s != '\0' && !ISSPACE (*s); ++s)
+ continue;
+
+ /* If we stopped on whitespace, then replace the whitespace with null for
+ the call to hash_find. Save the character we replaced just in case we
+ have to re-parse the instruction. */
+ if (ISSPACE (*s))
+ {
+ save_c = *s;
+ *s++ = '\0';
+ }
+
+ insn = (struct riscv_opcode *) hash_find (op_hash, str);
+
+ /* If we didn't find the instruction in the opcode table, try again, but
+ this time with just the instruction up to, but not including the
+ first '.'. */
+ if (insn == NULL)
+ {
+ /* Restore the character we overwrite above (if any). */
+ if (save_c)
+ *(--s) = save_c;
+
+ /* Scan up to the first '.' or whitespace. */
+ for (s = str;
+ *s != '\0' && *s != '.' && !ISSPACE (*s);
+ ++s)
+ continue;
+
+ /* If we did not find a '.', then we can quit now. */
+ if (*s != '.')
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+
+ /* Lookup the instruction in the hash table. */
+ *s++ = '\0';
+ if ((insn = (struct riscv_opcode *) hash_find (op_hash, str)) == NULL)
+ {
+ insn_error = "unrecognized opcode";
+ return;
+ }
+ }
+
+ argsStart = s;
+ for (;;)
+ {
+ bfd_boolean ok = TRUE;
+ gas_assert (strcmp (insn->name, str) == 0);
+
+ create_insn (ip, insn);
+ insn_error = NULL;
+ argnum = 1;
+ for (args = insn->args;; ++args)
+ {
+ s += strspn (s, " \t");
+ switch (*args)
+ {
+ case '\0': /* end of args */
+ if (*s == '\0')
+ return;
+ break;
+ /* Xcustom */
+ case '^':
+ {
+ unsigned long max = OP_MASK_RD;
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ switch (*++args)
+ {
+ case 'j':
+ max = OP_MASK_CUSTOM_IMM;
+ INSERT_OPERAND (CUSTOM_IMM, *ip, imm_expr.X_add_number);
+ break;
+ case 'd':
+ INSERT_OPERAND (RD, *ip, imm_expr.X_add_number);
+ break;
+ case 's':
+ INSERT_OPERAND (RS1, *ip, imm_expr.X_add_number);
+ break;
+ case 't':
+ INSERT_OPERAND (RS2, *ip, imm_expr.X_add_number);
+ break;
+ }
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ if ((unsigned long) imm_expr.X_add_number > max)
+ as_warn ("Bad custom immediate (%lu), must be at most %lu",
+ (unsigned long)imm_expr.X_add_number, max);
+ continue;
+ }
+
+ /* Xhwacha */
+ case '#':
+ switch ( *++args )
+ {
+ case 'g':
+ my_getExpression( &imm_expr, s );
+ /* check_absolute_expr( ip, &imm_expr ); */
+ if ((unsigned long) imm_expr.X_add_number > 32 )
+ as_warn( _( "Improper ngpr amount (%lu)" ),
+ (unsigned long) imm_expr.X_add_number );
+ INSERT_OPERAND( IMMNGPR, *ip, imm_expr.X_add_number );
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+ case 'f':
+ my_getExpression( &imm_expr, s );
+ /* check_absolute_expr( ip, &imm_expr ); */
+ if ((unsigned long) imm_expr.X_add_number > 32 )
+ as_warn( _( "Improper nfpr amount (%lu)" ),
+ (unsigned long) imm_expr.X_add_number );
+ INSERT_OPERAND( IMMNFPR, *ip, imm_expr.X_add_number );
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+ case 'n':
+ my_getExpression( &imm_expr, s );
+ /* check_absolute_expr( ip, &imm_expr ); */
+ if ((unsigned long) imm_expr.X_add_number > 8 )
+ as_warn( _( "Improper nelm amount (%lu)" ),
+ (unsigned long) imm_expr.X_add_number );
+ INSERT_OPERAND( IMMSEGNELM, *ip, imm_expr.X_add_number - 1 );
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+ case 'd':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VRD, *ip, regno );
+ continue;
+ case 's':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VRS, *ip, regno );
+ continue;
+ case 't':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VRT, *ip, regno );
+ continue;
+ case 'r':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VRR, *ip, regno );
+ continue;
+ case 'D':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VFD, *ip, regno );
+ continue;
+ case 'S':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VFS, *ip, regno );
+ continue;
+ case 'T':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VFT, *ip, regno );
+ continue;
+ case 'R':
+ ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, &regno );
+ if ( !ok )
+ as_bad( _( "Invalid vector register" ) );
+ INSERT_OPERAND( VFR, *ip, regno );
+ continue;
+ }
+ break;
+
+ case ',':
+ ++argnum;
+ if (*s++ == *args)
+ continue;
+ s--;
+ break;
+
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ if (*s++ == *args)
+ continue;
+ break;
+
+ case '<': /* must be at least one digit */
+ /*
+ * According to the manual, if the shift amount is greater
+ * than 31 or less than 0, then the shift amount should be
+ * mod 32. In reality the mips assembler issues an error.
+ * We issue a warning and mask out all but the low 5 bits.
+ */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > 31)
+ as_warn (_("Improper shift amount (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (SHAMTW, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case '>': /* shift amount, 0-63 */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > (rv64 ? 63 : 31))
+ as_warn (_("Improper shift amount (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'Z': /* CSRRxI immediate */
+ my_getExpression (&imm_expr, s);
+ check_absolute_expr (ip, &imm_expr);
+ if ((unsigned long) imm_expr.X_add_number > 31)
+ as_warn (_("Improper CSRxI immediate (%lu)"),
+ (unsigned long) imm_expr.X_add_number);
+ INSERT_OPERAND (RS1, *ip, imm_expr.X_add_number);
+ imm_expr.X_op = O_absent;
+ s = expr_end;
+ continue;
+
+ case 'E': /* Control register. */
+ ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, &regno);
+ INSERT_OPERAND (CSR, *ip, regno);
+ if (ok)
+ continue;
+ else
+ break;
+
+ case 'm': /* rounding mode */
+ if (arg_lookup (&s, riscv_rm, ARRAY_SIZE(riscv_rm), &regno))
+ {
+ INSERT_OPERAND (RM, *ip, regno);
+ continue;
+ }
+ break;
+
+ case 'P':
+ case 'Q': /* fence predecessor/successor */
+ if (arg_lookup (&s, riscv_pred_succ, ARRAY_SIZE(riscv_pred_succ), &regno))
+ {
+ if (*args == 'P')
+ INSERT_OPERAND(PRED, *ip, regno);
+ else
+ INSERT_OPERAND(SUCC, *ip, regno);
+ continue;
+ }
+ break;
+
+ case 'd': /* destination register */
+ case 's': /* source register */
+ case 't': /* target register */
+ ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
+ if (ok)
+ {
+ c = *args;
+ if (*s == ' ')
+ ++s;
+
+ /* Now that we have assembled one operand, we use the args string
+ * to figure out where it goes in the instruction. */
+ switch (c)
+ {
+ case 's':
+ INSERT_OPERAND (RS1, *ip, regno);
+ break;
+ case 'd':
+ INSERT_OPERAND (RD, *ip, regno);
+ break;
+ case 't':
+ INSERT_OPERAND (RS2, *ip, regno);
+ break;
+ }
+ continue;
+ }
+ break;
+
+ case 'D': /* floating point rd */
+ case 'S': /* floating point rs1 */
+ case 'T': /* floating point rs2 */
+ case 'U': /* floating point rs1 and rs2 */
+ case 'R': /* floating point rs3 */
+ rtype = RTYPE_FPU;
+ if (reg_lookup (&s, rtype, &regno))
+ {
+ c = *args;
+ if (*s == ' ')
+ ++s;
+ switch (c)
+ {
+ case 'D':
+ INSERT_OPERAND (RD, *ip, regno);
+ break;
+ case 'S':
+ INSERT_OPERAND (RS1, *ip, regno);
+ break;
+ case 'U':
+ INSERT_OPERAND (RS1, *ip, regno);
+ /* fallthru */
+ case 'T':
+ INSERT_OPERAND (RS2, *ip, regno);
+ break;
+ case 'R':
+ INSERT_OPERAND (RS3, *ip, regno);
+ break;
+ }
+ continue;
+ }
+
+ break;
+
+ case 'I':
+ my_getExpression (&imm_expr, s);
+ if (imm_expr.X_op != O_big
+ && imm_expr.X_op != O_constant)
+ insn_error = _("absolute expression required");
+ normalize_constant_expr (&imm_expr);
+ s = expr_end;
+ continue;
+
+ case 'A':
+ my_getExpression (&offset_expr, s);
+ normalize_address_expr (&offset_expr);
+ imm_reloc = BFD_RELOC_32;
+ s = expr_end;
+ continue;
+
+ case 'j': /* sign-extended immediate */
+ imm_reloc = BFD_RELOC_RISCV_LO12_I;
+ p = percent_op_itype;
+ goto alu_op;
+ case 'q': /* store displacement */
+ p = percent_op_stype;
+ offset_reloc = BFD_RELOC_RISCV_LO12_S;
+ goto load_store;
+ case 'o': /* load displacement */
+ p = percent_op_itype;
+ offset_reloc = BFD_RELOC_RISCV_LO12_I;
+ goto load_store;
+ case '0': /* AMO "displacement," which must be zero */
+ p = percent_op_rtype;
+ offset_reloc = BFD_RELOC_UNUSED;
+load_store:
+ /* Check whether there is only a single bracketed expression
+ left. If so, it must be the base register and the
+ constant must be zero. */
+ offset_expr.X_op = O_constant;
+ offset_expr.X_add_number = 0;
+ if (*s == '(' && strchr (s + 1, '(') == 0)
+ continue;
+alu_op:
+ /* If this value won't fit into a 16 bit offset, then go
+ find a macro that will generate the 32 bit offset
+ code pattern. */
+ if (!my_getSmallExpression (&offset_expr, &offset_reloc, s, p))
+ {
+ normalize_constant_expr (&offset_expr);
+ if (offset_expr.X_op != O_constant
+ || (*args == '0' && offset_expr.X_add_number != 0)
+ || offset_expr.X_add_number >= (signed)RISCV_IMM_REACH/2
+ || offset_expr.X_add_number < -(signed)RISCV_IMM_REACH/2)
+ break;
+ }
+
+ s = expr_end;
+ continue;
+
+ case 'p': /* pc relative offset */
+ offset_reloc = BFD_RELOC_12_PCREL;
+ my_getExpression (&offset_expr, s);
+ s = expr_end;
+ continue;
+
+ case 'u': /* upper 20 bits */
+ p = percent_op_utype;
+ if (!my_getSmallExpression (&imm_expr, &imm_reloc, s, p)
+ && imm_expr.X_op == O_constant)
+ {
+ if (imm_expr.X_add_number < 0
+ || imm_expr.X_add_number >= (signed)RISCV_BIGIMM_REACH)
+ as_bad (_("lui expression not in range 0..1048575"));
+
+ imm_reloc = BFD_RELOC_RISCV_HI20;
+ imm_expr.X_add_number <<= RISCV_IMM_BITS;
+ }
+ s = expr_end;
+ continue;
+
+ case 'a': /* 26 bit address */
+ my_getExpression (&offset_expr, s);
+ s = expr_end;
+ offset_reloc = BFD_RELOC_MIPS_JMP;
+ continue;
+
+ case 'c':
+ my_getExpression (&offset_expr, s);
+ s = expr_end;
+ offset_reloc = BFD_RELOC_RISCV_CALL;
+ if (*s == '@')
+ offset_reloc = BFD_RELOC_RISCV_CALL_PLT, s++;
+ continue;
+
+ default:
+ as_bad (_("bad char = '%c'\n"), *args);
+ internalError ();
+ }
+ break;
+ }
+ /* Args don't match. */
+ if (insn + 1 < &riscv_opcodes[NUMOPCODES] &&
+ !strcmp (insn->name, insn[1].name))
+ {
+ ++insn;
+ s = argsStart;
+ insn_error = _("illegal operands");
+ continue;
+ }
+ if (save_c)
+ *(--argsStart) = save_c;
+ insn_error = _("illegal operands");
+ return;
+ }
+}
+
+static void
+my_getExpression (expressionS *ep, char *str)
+{
+ char *save_in;
+
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ expression (ep);
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+}
+
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ return ieee_md_atof (type, litP, sizeP, TARGET_BYTES_BIG_ENDIAN);
+}
+
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+ number_to_chars_littleendian (buf, val, n);
+}
+
+const char *md_shortopts = "O::g::G:";
+
+enum options
+ {
+ OPTION_M32 = OPTION_MD_BASE,
+ OPTION_M64,
+ OPTION_MARCH,
+ OPTION_PIC,
+ OPTION_NO_PIC,
+ OPTION_MRVC,
+ OPTION_MNO_RVC,
+ OPTION_END_OF_ENUM
+ };
+
+struct option md_longopts[] =
+{
+ {"m32", no_argument, NULL, OPTION_M32},
+ {"m64", no_argument, NULL, OPTION_M64},
+ {"march", required_argument, NULL, OPTION_MARCH},
+ {"fPIC", no_argument, NULL, OPTION_PIC},
+ {"fpic", no_argument, NULL, OPTION_PIC},
+ {"fno-pic", no_argument, NULL, OPTION_NO_PIC},
+ {"mrvc", no_argument, NULL, OPTION_MRVC},
+ {"mno-rvc", no_argument, NULL, OPTION_MNO_RVC},
+
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+int
+md_parse_option (int c, char *arg)
+{
+ switch (c)
+ {
+ case 'g':
+ if (arg == NULL)
+ mips_debug = 2;
+ else
+ mips_debug = atoi (arg);
+ break;
+
+ case OPTION_MRVC:
+ mips_opts.rvc = 1;
+ break;
+
+ case OPTION_MNO_RVC:
+ mips_opts.rvc = 0;
+ break;
+
+ case OPTION_M32:
+ rv64 = FALSE;
+ break;
+
+ case OPTION_M64:
+ rv64 = TRUE;
+ break;
+
+ case OPTION_MARCH:
+ riscv_set_arch(arg);
+
+ case OPTION_NO_PIC:
+ is_pic = FALSE;
+ break;
+
+ case OPTION_PIC:
+ is_pic = TRUE;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+mips_after_parse_args (void)
+{
+ if (riscv_subsets == NULL)
+ riscv_set_arch("RVIMAFDXcustom");
+}
+
+void
+mips_init_after_args (void)
+{
+ /* initialize opcodes */
+ bfd_riscv_num_opcodes = bfd_riscv_num_builtin_opcodes;
+ riscv_opcodes = (struct riscv_opcode *) riscv_builtin_opcodes;
+}
+
+long
+md_pcrel_from (fixS *fixP)
+{
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/* Apply a fixup to the object file. */
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+ bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
+ bfd_reloc_code_real_type pcrel_r_type;
+
+ /* We ignore generic BFD relocations we don't know about. */
+ if (! bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type))
+ return;
+
+ /* Remember value for tc_gen_reloc. */
+ fixP->fx_addnumber = *valP;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_MIPS_TLS_DTPREL32:
+ case BFD_RELOC_MIPS_TLS_DTPREL64:
+ case BFD_RELOC_RISCV_TPREL_HI20:
+ case BFD_RELOC_RISCV_TPREL_LO12_I:
+ case BFD_RELOC_RISCV_TPREL_LO12_S:
+ case BFD_RELOC_RISCV_TPREL_ADD:
+ case BFD_RELOC_RISCV_TLS_IE_HI20:
+ case BFD_RELOC_RISCV_TLS_IE_LO12:
+ case BFD_RELOC_RISCV_TLS_IE_ADD:
+ case BFD_RELOC_RISCV_TLS_IE_LO12_I:
+ case BFD_RELOC_RISCV_TLS_IE_LO12_S:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ /* fall through */
+
+ case BFD_RELOC_RISCV_TLS_GOT_HI20:
+ case BFD_RELOC_RISCV_TLS_GD_HI20:
+ case BFD_RELOC_RISCV_GOT_HI20:
+ case BFD_RELOC_RISCV_PCREL_HI20:
+ case BFD_RELOC_RISCV_HI20:
+ case BFD_RELOC_RISCV_LO12_I:
+ case BFD_RELOC_RISCV_LO12_S:
+ case BFD_RELOC_RISCV_ADD32:
+ case BFD_RELOC_RISCV_ADD64:
+ case BFD_RELOC_RISCV_SUB32:
+ case BFD_RELOC_RISCV_SUB64:
+ gas_assert (fixP->fx_addsy != NULL);
+ /* Nothing needed to do. The value comes from the reloc entry. */
+ return;
+
+ case BFD_RELOC_64:
+ case BFD_RELOC_32:
+ if (fixP->fx_addsy && fixP->fx_subsy)
+ {
+ fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
+ fixP->fx_next->fx_addsy = fixP->fx_subsy;
+ fixP->fx_next->fx_subsy = NULL;
+ fixP->fx_next->fx_offset = 0;
+ fixP->fx_subsy = NULL;
+
+ if (fixP->fx_r_type == BFD_RELOC_64)
+ fixP->fx_r_type = BFD_RELOC_RISCV_ADD64,
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB64;
+ else
+ fixP->fx_r_type = BFD_RELOC_RISCV_ADD32,
+ fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB32;
+ }
+ /* fall through */
+
+ case BFD_RELOC_RVA:
+ /* If we are deleting this reloc entry, we must fill in the
+ value now. This can happen if we have a .word which is not
+ resolved when it appears but is later defined. */
+ if (fixP->fx_addsy == NULL)
+ {
+ gas_assert (fixP->fx_size <= sizeof (valueT));
+ md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
+ fixP->fx_done = 1;
+ }
+ return;
+
+ case BFD_RELOC_RISCV_TLS_GOT_LO12:
+ case BFD_RELOC_RISCV_TLS_GD_LO12:
+ gas_assert (fixP->fx_addsy != NULL);
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ pcrel_r_type = BFD_RELOC_RISCV_TLS_PCREL_LO12;
+ break;
+
+ case BFD_RELOC_RISCV_GOT_LO12:
+ gas_assert (fixP->fx_addsy != NULL);
+ pcrel_r_type = BFD_RELOC_RISCV_PCREL_LO12_I;
+ break;
+
+ case BFD_RELOC_RISCV_PCREL_LO12_S:
+ if (fixP->fx_addsy != NULL)
+ {
+ fixP->fx_r_type = BFD_RELOC_RISCV_LO12_S;
+ pcrel_r_type = BFD_RELOC_RISCV_PCREL_LO12_S;
+ break;
+ }
+ return;
+
+ case BFD_RELOC_RISCV_PCREL_LO12_I:
+ if (fixP->fx_addsy != NULL)
+ {
+ fixP->fx_r_type = BFD_RELOC_RISCV_LO12_I;
+ pcrel_r_type = BFD_RELOC_RISCV_PCREL_LO12_I;
+ break;
+ }
+ return;
+
+ case BFD_RELOC_RISCV_TLS_PCREL_LO12:
+ case BFD_RELOC_RISCV_CALL:
+ case BFD_RELOC_RISCV_CALL_PLT:
+ case BFD_RELOC_MIPS_JMP:
+ case BFD_RELOC_12_PCREL:
+ return;
+
+ default:
+ internalError ();
+ }
+
+ /* We only get here for the low part of split PC-relative relocs.
+ Record the distance between the high and low parts. For now,
+ we assume the high part (AUIPC) is immediately before us, and
+ so this distance is -4. */
+ gas_assert (fixP->fx_subsy == NULL);
+ fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
+ fixP->fx_next->fx_addsy = NULL;
+ fixP->fx_next->fx_offset = -4;
+ fixP->fx_next->fx_r_type = pcrel_r_type;
+}
+
+/* Align the current frag to a given power of two. If a particular
+ fill byte should be used, FILL points to an integer that contains
+ that byte, otherwise FILL is null.
+
+ The MIPS assembler also automatically adjusts any preceding
+ label. */
+
+static void
+mips_align (int to, int *fill, symbolS *label)
+{
+ mips_clear_insn_labels ();
+ if (fill == NULL && subseg_text_p (now_seg))
+ frag_align_code (to, 0);
+ else
+ frag_align (to, fill ? *fill : 0, 0);
+ record_alignment (now_seg, to);
+ if (label != NULL)
+ {
+ gas_assert (S_GET_SEGMENT (label) == now_seg);
+ symbol_set_frag (label, frag_now);
+ S_SET_VALUE (label, (valueT) frag_now_fix ());
+ }
+}
+
+/* Align to a given power of two. .align 0 turns off the automatic
+ alignment used by the data creating pseudo-ops. */
+
+static void
+s_align (int x ATTRIBUTE_UNUSED)
+{
+ int temp, fill_value, *fill_ptr;
+ long max_alignment = 28;
+
+ /* o Note that the assembler pulls down any immediately preceding label
+ to the aligned address.
+ o It's not documented but auto alignment is reinstated by
+ a .align pseudo instruction.
+ o Note also that after auto alignment is turned off the mips assembler
+ issues an error on attempt to assemble an improperly aligned data item.
+ We don't. */
+
+ temp = get_absolute_expression ();
+ if (temp > max_alignment)
+ as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
+ else if (temp < 0)
+ {
+ as_warn (_("Alignment negative: 0 assumed."));
+ temp = 0;
+ }
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ fill_value = get_absolute_expression ();
+ fill_ptr = &fill_value;
+ }
+ else
+ fill_ptr = 0;
+ if (temp)
+ {
+ segment_info_type *si = seg_info (now_seg);
+ struct insn_label_list *l = si->label_list;
+ /* Auto alignment should be switched on by next section change. */
+ auto_align = 1;
+ mips_align (temp, fill_ptr, l != NULL ? l->label : NULL);
+ }
+ else
+ {
+ auto_align = 0;
+ }
+
+ demand_empty_rest_of_line ();
+}
+
+static void
+s_change_sec (int sec)
+{
+#ifdef OBJ_ELF
+ /* The ELF backend needs to know that we are changing sections, so
+ that .previous works correctly. We could do something like check
+ for an obj_section_change_hook macro, but that might be confusing
+ as it would not be appropriate to use it in the section changing
+ functions in read.c, since obj-elf.c intercepts those. FIXME:
+ This should be cleaner, somehow. */
+ if (IS_ELF)
+ obj_elf_section_change_hook ();
+#endif
+
+ mips_clear_insn_labels ();
+
+ switch (sec)
+ {
+ case 't':
+ s_text (0);
+ break;
+ case 'd':
+ s_data (0);
+ break;
+ case 'b':
+ subseg_set (bss_section, (subsegT) get_absolute_expression ());
+ demand_empty_rest_of_line ();
+ break;
+ case 'r':
+ subseg_new (".rodata", (subsegT) get_absolute_expression ());
+ demand_empty_rest_of_line ();
+ break;
+ }
+
+ auto_align = 1;
+}
+
+void
+s_change_section (int ignore ATTRIBUTE_UNUSED)
+{
+#ifdef OBJ_ELF
+ char *section_name;
+ char c;
+ char next_c = 0;
+ int section_type;
+ int section_flag;
+ int section_entry_size;
+
+ if (!IS_ELF)
+ return;
+
+ section_name = input_line_pointer;
+ c = get_symbol_end ();
+ if (c)
+ next_c = *(input_line_pointer + 1);
+
+ /* Do we have .section Name<,"flags">? */
+ if (c != ',' || (c == ',' && next_c == '"'))
+ {
+ /* just after name is now '\0'. */
+ *input_line_pointer = c;
+ input_line_pointer = section_name;
+ obj_elf_section (ignore);
+ return;
+ }
+ input_line_pointer++;
+
+ /* Do we have .section Name<,type><,flag><,entry_size><,alignment> */
+ if (c == ',')
+ section_type = get_absolute_expression ();
+ else
+ section_type = 0;
+ if (*input_line_pointer++ == ',')
+ section_flag = get_absolute_expression ();
+ else
+ section_flag = 0;
+ if (*input_line_pointer++ == ',')
+ section_entry_size = get_absolute_expression ();
+ else
+ section_entry_size = 0;
+
+ section_name = xstrdup (section_name);
+
+ obj_elf_change_section (section_name, section_type, section_flag,
+ section_entry_size, 0, 0, 0);
+
+ if (now_seg->name != section_name)
+ free (section_name);
+#endif /* OBJ_ELF */
+}
+
+void
+mips_enable_auto_align (void)
+{
+ auto_align = 1;
+}
+
+static void
+s_cons (int log_size)
+{
+ segment_info_type *si = seg_info (now_seg);
+ struct insn_label_list *l = si->label_list;
+ symbolS *label;
+
+ label = l != NULL ? l->label : NULL;
+ mips_clear_insn_labels ();
+ if (log_size > 0 && auto_align)
+ mips_align (log_size, 0, label);
+ mips_clear_insn_labels ();
+ cons (1 << log_size);
+}
+
+static void
+s_float_cons (int type)
+{
+ segment_info_type *si = seg_info (now_seg);
+ struct insn_label_list *l = si->label_list;
+ symbolS *label;
+
+ label = l != NULL ? l->label : NULL;
+
+ mips_clear_insn_labels ();
+
+ if (auto_align)
+ {
+ if (type == 'd')
+ mips_align (3, 0, label);
+ else
+ mips_align (2, 0, label);
+ }
+
+ mips_clear_insn_labels ();
+
+ float_cons (type);
+}
+
+/* This structure is used to hold a stack of .set values. */
+
+struct mips_option_stack
+{
+ struct mips_option_stack *next;
+ struct mips_set_options options;
+};
+
+static struct mips_option_stack *mips_opts_stack;
+
+/* Handle the .set pseudo-op. */
+
+static void
+s_riscv_option (int x ATTRIBUTE_UNUSED)
+{
+ char *name = input_line_pointer, ch;
+
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ ++input_line_pointer;
+ ch = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ if (strcmp (name, "rvc") == 0)
+ mips_opts.rvc = 1;
+ else if (strcmp (name, "norvc") == 0)
+ mips_opts.rvc = 0;
+ else if (strcmp (name, "push") == 0)
+ {
+ struct mips_option_stack *s;
+
+ s = (struct mips_option_stack *) xmalloc (sizeof *s);
+ s->next = mips_opts_stack;
+ s->options = mips_opts;
+ mips_opts_stack = s;
+ }
+ else if (strcmp (name, "pop") == 0)
+ {
+ struct mips_option_stack *s;
+
+ s = mips_opts_stack;
+ if (s == NULL)
+ as_bad (_(".set pop with no .set push"));
+ else
+ {
+ mips_opts = s->options;
+ mips_opts_stack = s->next;
+ free (s);
+ }
+ }
+ else if (strchr (name, ','))
+ {
+ /* Generic ".set" directive; use the generic handler. */
+ *input_line_pointer = ch;
+ input_line_pointer = name;
+ s_set (0);
+ return;
+ }
+ else
+ {
+ as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
+ }
+ *input_line_pointer = ch;
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
+ a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
+ use in DWARF debug information. */
+
+static void
+s_dtprel_internal (size_t bytes)
+{
+ expressionS ex;
+ char *p;
+
+ expression (&ex);
+
+ if (ex.X_op != O_symbol)
+ {
+ as_bad (_("Unsupported use of %s"), (bytes == 8
+ ? ".dtpreldword"
+ : ".dtprelword"));
+ ignore_rest_of_line ();
+ }
+
+ p = frag_more (bytes);
+ md_number_to_chars (p, 0, bytes);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
+ (bytes == 8
+ ? BFD_RELOC_MIPS_TLS_DTPREL64
+ : BFD_RELOC_MIPS_TLS_DTPREL32));
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle .dtprelword. */
+
+static void
+s_dtprelword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_dtprel_internal (4);
+}
+
+/* Handle .dtpreldword. */
+
+static void
+s_dtpreldword (int ignore ATTRIBUTE_UNUSED)
+{
+ s_dtprel_internal (8);
+}
+
+/* Compute the length of a branch sequence, and adjust the
+ RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the
+ worst-case length is computed. */
+static int
+relaxed_branch_length (fragS *fragp, asection *sec, int update)
+{
+ bfd_boolean toofar_rvc = TRUE, toofar = TRUE;
+
+ if (fragp)
+ {
+ bfd_boolean uncond = RELAX_BRANCH_UNCOND (fragp->fr_subtype);
+ bfd_boolean rvc = RELAX_BRANCH_RVC (fragp->fr_subtype);
+
+ if (S_IS_DEFINED (fragp->fr_symbol)
+ && sec == S_GET_SEGMENT (fragp->fr_symbol))
+ {
+ offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ bfd_vma range;
+ val -= fragp->fr_address + fragp->fr_fix;
+
+ if (uncond && rvc)
+ range = RVC_JUMP_REACH;
+ else if (rvc)
+ range = RVC_BRANCH_REACH;
+ else if (uncond)
+ range = RISCV_JUMP_REACH;
+ else
+ range = RISCV_BRANCH_REACH;
+ toofar = (bfd_vma)(val + range/2) >= range;
+ }
+
+ if (update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+ fragp->fr_subtype = RELAX_BRANCH_ENCODE (uncond, rvc, toofar);
+ }
+
+ return toofar ? 8 : toofar_rvc ? 4 : 2;
+}
+
+int
+md_estimate_size_before_relax (fragS *fragp, asection *segtype)
+{
+ return (fragp->fr_var = relaxed_branch_length (fragp, segtype, FALSE));
+}
+
+/* Translate internal representation of relocation info to BFD target
+ format. */
+
+arelent **
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+{
+ static arelent *retval[4];
+ arelent *reloc;
+ bfd_reloc_code_real_type code;
+
+ memset (retval, 0, sizeof(retval));
+ reloc = retval[0] = (arelent *) xcalloc (1, sizeof (arelent));
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ if (fixp->fx_pcrel)
+ /* At this point, fx_addnumber is "symbol offset - pcrel address".
+ Relocations want only the symbol offset. */
+ reloc->addend = fixp->fx_addnumber + reloc->address;
+ else
+ reloc->addend = fixp->fx_addnumber;
+
+ code = fixp->fx_r_type;
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (reloc->howto == NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("Can not represent %s relocation in this object file format"),
+ bfd_get_reloc_code_name (code));
+ retval[0] = NULL;
+ }
+
+ return retval;
+}
+
+int
+mips_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
+{
+ if (RELAX_BRANCH_P (fragp->fr_subtype))
+ {
+ offsetT old_var = fragp->fr_var;
+ fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE);
+ return fragp->fr_var - old_var;
+ }
+
+ return 0;
+}
+
+/* Convert a machine dependent frag. */
+
+static void
+md_convert_frag_branch (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED,
+ fragS *fragp)
+{
+ bfd_byte *buf;
+ insn_t insn;
+ expressionS exp;
+ fixS *fixp;
+
+ buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
+
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = fragp->fr_symbol;
+ exp.X_add_number = fragp->fr_offset;
+
+#if 0
+ if (RELAX_BRANCH_RVC (fragp->fr_subtype))
+ {
+ if (RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+ {
+ bfd_reloc_code_real_type reloc_type = BFD_RELOC_12_PCREL;
+
+ gas_assert(fragp->fr_var == 4);
+ insn = bfd_getl16 (buf);
+
+ int rs1 = rvc_rs1_regmap[(insn >> OP_SH_CRS1S) & OP_MASK_CRS1S];
+ int rs2 = rvc_rs2_regmap[(insn >> OP_SH_CRS2S) & OP_MASK_CRS2S];
+
+ if((insn & MASK_C_J) == MATCH_C_J)
+ {
+ insn = MATCH_JAL;
+ reloc_type = BFD_RELOC_MIPS_JMP;
+ }
+ else if((insn & MASK_C_BEQ) == MATCH_C_BEQ)
+ insn = MATCH_BEQ | (rs1 << OP_SH_RS1) | (rs2 << OP_SH_RS2);
+ else if((insn & MASK_C_BNE) == MATCH_C_BNE)
+ insn = MATCH_BNE | (rs1 << OP_SH_RS1) | (rs2 << OP_SH_RS2);
+ else
+ gas_assert(0);
+
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+ 4, &exp, FALSE, reloc_type);
+ md_number_to_chars ((char *) buf, insn, 4);
+ buf += 4;
+ }
+ else
+ {
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+ 2, &exp, FALSE, BFD_RELOC_12_PCREL);
+ buf += 2;
+ }
+ }
+ else
+#endif
+ {
+ if (RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+ {
+ gas_assert (fragp->fr_var == 8);
+ /* We could relax JAL to AUIPC/JALR, but we don't do this yet. */
+ gas_assert (!RELAX_BRANCH_UNCOND (fragp->fr_subtype));
+
+ /* Invert the branch condition. Branch over the jump. */
+ insn = bfd_getl32 (buf);
+ insn ^= MATCH_BEQ ^ MATCH_BNE;
+ insn |= ENCODE_SBTYPE_IMM (8);
+ md_number_to_chars ((char *) buf, insn, 4);
+ buf += 4;
+
+ /* Jump to the target. */
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+ 4, &exp, FALSE, BFD_RELOC_MIPS_JMP);
+ md_number_to_chars ((char *) buf, MATCH_JAL, 4);
+ buf += 4;
+ }
+ else
+ {
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+ 4, &exp, FALSE, BFD_RELOC_12_PCREL);
+ buf += 4;
+ }
+ }
+
+ fixp->fx_file = fragp->fr_file;
+ fixp->fx_line = fragp->fr_line;
+ fixp->fx_pcrel = 1;
+
+ gas_assert (buf == (bfd_byte *)fragp->fr_literal
+ + fragp->fr_fix + fragp->fr_var);
+
+ fragp->fr_fix += fragp->fr_var;
+}
+
+/* Relax a machine dependent frag. This returns the amount by which
+ the current size of the frag should change. */
+
+void
+md_convert_frag(bfd *abfd, segT asec, fragS *fragp)
+{
+ if(RELAX_BRANCH_P(fragp->fr_subtype))
+ md_convert_frag_branch(abfd, asec, fragp);
+ else
+ gas_assert(0);
+}
+
+/* This function is called whenever a label is defined. It is used
+ when handling branch delays; if a branch has a label, we assume we
+ can not move it. */
+
+void
+mips_define_label (symbolS *sym)
+{
+ segment_info_type *si = seg_info (now_seg);
+ struct insn_label_list *l;
+
+ if (free_insn_labels == NULL)
+ l = (struct insn_label_list *) xmalloc (sizeof *l);
+ else
+ {
+ l = free_insn_labels;
+ free_insn_labels = l->next;
+ }
+
+ l->label = sym;
+ l->next = si->label_list;
+ si->label_list = l;
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
+}
+
+void
+mips_handle_align (fragS *fragp)
+{
+ char *p;
+
+ if (fragp->fr_type != rs_align_code)
+ return;
+
+ p = fragp->fr_literal + fragp->fr_fix;
+ md_number_to_chars (p, RISCV_NOP, 4);
+ fragp->fr_var = 4;
+}
+
+void
+md_show_usage (FILE *stream)
+{
+ fprintf (stream, _("\
+RISC-V options:\n\
+ -m32 assemble RV32 code\n\
+ -m64 assemble RV64 code (default)\n\
+ -fpic generate position-independent code\n\
+ -fno-pic don't generate position-independent code (default)\n\
+"));
+}
+
+enum dwarf2_format
+mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
+{
+ if (HAVE_32BIT_SYMBOLS)
+ return dwarf2_format_32bit;
+ else
+ return dwarf2_format_64bit;
+}
+
+int
+mips_dwarf2_addr_size (void)
+{
+ return rv64 ? 8 : 4;
+}
+
+/* Standard calling conventions leave the CFA at SP on entry. */
+void
+mips_cfi_frame_initial_instructions (void)
+{
+ cfi_add_CFA_def_cfa_register (SP);
+}
+
+int
+tc_mips_regname_to_dw2regnum (char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int reg;
+
+ if (reg_lookup (&regname, RTYPE_GP | RTYPE_NUM, &reg))
+ regnum = reg;
+
+ return regnum;
+}
+
+void
+riscv_elf_final_processing (void)
+{
+ struct riscv_subset* s;
+
+ unsigned int Xlen = 0;
+ for (s = riscv_subsets; s != NULL; s = s->next)
+ if (s->name[0] == 'X')
+ Xlen += strlen(s->name);
+
+ char extension[Xlen];
+ extension[0] = 0;
+ for (s = riscv_subsets; s != NULL; s = s->next)
+ if (s->name[0] == 'X')
+ strcat(extension, s->name);
+
+ EF_SET_RISCV_EXT(elf_elfheader (stdoutput)->e_flags,
+ riscv_elf_name_to_flag (extension));
+}
diff --git a/binutils-2.21.1/gas/config/tc-riscv.h b/binutils-2.21.1/gas/config/tc-riscv.h
new file mode 100644
index 0000000..a9a8c37
--- /dev/null
+++ binutils-2.21.1/gas/config/tc-riscv.h
@@ -0,0 +1,132 @@
+/* tc-mips.h -- header file for tc-mips.c.
+ Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007 Free Software Foundation, Inc.
+ Contributed by the OSF and Ralph Campbell.
+ Written by Keith Knowles and Ralph Campbell, working independently.
+ Modified for ECOFF support by Ian Lance Taylor of Cygnus Support.
+
+ This file is part of GAS.
+
+ GAS 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, or (at your option)
+ any later version.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef TC_RISCV
+#define TC_RISCV
+
+#include "opcode/riscv.h"
+
+struct frag;
+struct expressionS;
+
+#define TARGET_BYTES_BIG_ENDIAN 0
+
+#define TARGET_ARCH bfd_arch_riscv
+
+#define WORKING_DOT_WORD 1
+#define OLD_FLOAT_READS
+#define REPEAT_CONS_EXPRESSIONS
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 3
+#define LOCAL_LABELS_FB 1
+
+#define md_relax_frag(segment, fragp, stretch) \
+ mips_relax_frag(segment, fragp, stretch)
+extern int mips_relax_frag (asection *, struct frag *, long);
+
+#define md_section_align(seg,size) (size)
+#define md_undefined_symbol(name) (0)
+#define md_operand(x)
+
+#define NOP_OPCODE RISCV_NOP
+
+extern void mips_handle_align (struct frag *);
+#define HANDLE_ALIGN(fragp) mips_handle_align (fragp)
+
+#define MAX_MEM_FOR_RS_ALIGN_CODE (1 + 2)
+
+struct insn_label_list;
+struct mips_segment_info {
+ struct insn_label_list *labels;
+ unsigned int mips16 : 1;
+};
+#define TC_SEGMENT_INFO_TYPE struct mips_segment_info
+
+/* This field is nonzero if the symbol is the target of a MIPS16 jump. */
+#define TC_SYMFIELD_TYPE int
+
+/* The ISA of the target may change based on command-line arguments. */
+#define TARGET_FORMAT mips_target_format()
+extern const char *mips_target_format (void);
+
+#define md_after_parse_args() mips_after_parse_args()
+extern void mips_after_parse_args (void);
+
+#define tc_init_after_args() mips_init_after_args()
+extern void mips_init_after_args (void);
+
+#define md_parse_long_option(arg) mips_parse_long_option (arg)
+extern int mips_parse_long_option (const char *);
+
+#define tc_frob_label(sym) mips_define_label (sym)
+extern void mips_define_label (symbolS *);
+
+/* Let the linker resolve all the relocs due to relaxation. */
+#define tc_fix_adjustable(fixp) 0
+#define md_allow_local_subtract(l,r,s) 0
+
+/* Values passed to md_apply_fix don't include symbol values. */
+#define MD_APPLY_SYM_VALUE(FIX) 0
+
+/* Global syms must not be resolved, to support ELF shared libraries. */
+#define EXTERN_FORCE_RELOC \
+ (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+
+#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) ((SEG)->flags & SEC_CODE)
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) 1
+#define TC_VALIDATE_FIX_SUB(FIX, SEG) TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG)
+#define DIFF_EXPR_OK 1
+
+extern void mips_pop_insert (void);
+#define md_pop_insert() mips_pop_insert()
+
+extern void mips_clear_insn_labels (void);
+#define md_flush_pending_output mips_clear_insn_labels
+
+extern void mips_enable_auto_align (void);
+#define md_elf_section_change_hook() mips_enable_auto_align()
+
+enum dwarf2_format;
+extern enum dwarf2_format mips_dwarf2_format (asection *);
+#define DWARF2_FORMAT(SEC) mips_dwarf2_format (SEC)
+
+extern int mips_dwarf2_addr_size (void);
+#define DWARF2_ADDR_SIZE(bfd) mips_dwarf2_addr_size ()
+#define DWARF2_FDE_RELOC_SIZE mips_dwarf2_addr_size ()
+
+#define TARGET_USE_CFIPOP 1
+
+#define tc_cfi_frame_initial_instructions mips_cfi_frame_initial_instructions
+extern void mips_cfi_frame_initial_instructions (void);
+
+#define tc_regname_to_dw2regnum tc_mips_regname_to_dw2regnum
+extern int tc_mips_regname_to_dw2regnum (char *regname);
+
+#define DWARF2_DEFAULT_RETURN_COLUMN LINK_REG
+#define DWARF2_CIE_DATA_ALIGNMENT (-4)
+
+#define elf_tc_final_processing riscv_elf_final_processing
+extern void riscv_elf_final_processing (void);
+
+#endif /* TC_RISCV */
diff --git a/binutils-2.21.1/gas/configure.tgt b/binutils-2.21.1/gas/configure.tgt
index aa12fbb..371c673 100644
--- a/binutils-2.21.1/gas/configure.tgt
+++ binutils-2.21.1/gas/configure.tgt
@@ -63,6 +63,7 @@ case ${cpu} in
pj*) cpu_type=pj endian=big ;;
powerpc*le*) cpu_type=ppc endian=little ;;
powerpc*) cpu_type=ppc endian=big ;;
+ riscv*) cpu_type=riscv endian=little ;;
rs6000*) cpu_type=ppc ;;
rx) cpu_type=rx ;;
s390x*) cpu_type=s390 arch=s390x ;;
@@ -340,6 +341,8 @@ case ${generic_target} in
ppc-*-kaos*) fmt=elf ;;
ppc-*-lynxos*) fmt=elf em=lynx ;;
+ riscv*-*-*) fmt=elf endian=little em=linux bfd_gas=yes ;;
+
s390-*-linux-*) fmt=elf em=linux ;;
s390-*-tpf*) fmt=elf ;;
diff --git a/binutils-2.21.1/gas/doc/c-arc.texi b/binutils-2.21.1/gas/doc/c-arc.texi
index 3a136a7..cd6f0d9 100644
--- a/binutils-2.21.1/gas/doc/c-arc.texi
+++ binutils-2.21.1/gas/doc/c-arc.texi
@@ -212,7 +212,7 @@ The extension instructions are not macros. The assembler creates
encodings for use of these instructions according to the specification
by the user. The parameters are:
-@table @bullet
+@table @code
@item @var{name}
Name of the extension instruction
diff --git a/binutils-2.21.1/gas/doc/c-arm.texi b/binutils-2.21.1/gas/doc/c-arm.texi
index d3cccf4..97c2f92 100644
--- a/binutils-2.21.1/gas/doc/c-arm.texi
+++ binutils-2.21.1/gas/doc/c-arm.texi
@@ -376,29 +376,29 @@ ARM and THUMB instructions had their own, separate syntaxes. The new,
@code{unified} syntax, which can be selected via the @code{.syntax}
directive, and has the following main features:
-@table @bullet
-@item
+@table @code
+@item 1
Immediate operands do not require a @code{#} prefix.
-@item
+@item 2
The @code{IT} instruction may appear, and if it does it is validated
against subsequent conditional affixes. In ARM mode it does not
generate machine code, in THUMB mode it does.
-@item
+@item 3
For ARM instructions the conditional affixes always appear at the end
of the instruction. For THUMB instructions conditional affixes can be
used, but only inside the scope of an @code{IT} instruction.
-@item
+@item 4
All of the instructions new to the V6T2 architecture (and later) are
available. (Only a few such instructions can be written in the
@code{divided} syntax).
-@item
+@item 5
The @code{.N} and @code{.W} suffixes are recognized and honored.
-@item
+@item 6
All instructions set the flags if and only if they have an @code{s}
affix.
@end table
@@ -433,28 +433,6 @@ Either @samp{#} or @samp{$} can be used to indicate immediate operands.
@cindex register names, ARM
*TODO* Explain about ARM register naming, and the predefined names.
-@node ARM-Neon-Alignment
-@subsection NEON Alignment Specifiers
-
-@cindex alignment for NEON instructions
-Some NEON load/store instructions allow an optional address
-alignment qualifier.
-The ARM documentation specifies that this is indicated by
-@samp{@@ @var{align}}. However GAS already interprets
-the @samp{@@} character as a "line comment" start,
-so @samp{: @var{align}} is used instead. For example:
-
-@smallexample
- vld1.8 @{q0@}, [r0, :128]
-@end smallexample
-
-@node ARM Floating Point
-@section Floating Point
-
-@cindex floating point, ARM (@sc{ieee})
-@cindex ARM floating point (@sc{ieee})
-The ARM family uses @sc{ieee} floating-point numbers.
-
@node ARM-Relocations
@subsection ARM relocation generation
@@ -497,6 +475,28 @@ respectively. For example to load the 32-bit address of foo into r0:
MOVT r0, #:upper16:foo
@end smallexample
+@node ARM-Neon-Alignment
+@subsection NEON Alignment Specifiers
+
+@cindex alignment for NEON instructions
+Some NEON load/store instructions allow an optional address
+alignment qualifier.
+The ARM documentation specifies that this is indicated by
+@samp{@@ @var{align}}. However GAS already interprets
+the @samp{@@} character as a "line comment" start,
+so @samp{: @var{align}} is used instead. For example:
+
+@smallexample
+ vld1.8 @{q0@}, [r0, :128]
+@end smallexample
+
+@node ARM Floating Point
+@section Floating Point
+
+@cindex floating point, ARM (@sc{ieee})
+@cindex ARM floating point (@sc{ieee})
+The ARM family uses @sc{ieee} floating-point numbers.
+
@node ARM Directives
@section ARM Machine Directives
diff --git a/binutils-2.21.1/gas/doc/c-cr16.texi b/binutils-2.21.1/gas/doc/c-cr16.texi
index b6cf10f..3332426 100644
--- a/binutils-2.21.1/gas/doc/c-cr16.texi
+++ binutils-2.21.1/gas/doc/c-cr16.texi
@@ -43,26 +43,33 @@ Operand expression type qualifier is an optional field in the instruction operan
CR16 target operand qualifiers and its size (in bits):
@table @samp
-@item Immediate Operand
-- s ---- 4 bits
-@item
-- m ---- 16 bits, for movb and movw instructions.
-@item
-- m ---- 20 bits, movd instructions.
-@item
-- l ---- 32 bits
-
-@item Absolute Operand
-- s ---- Illegal specifier for this operand.
-@item
-- m ---- 20 bits, movd instructions.
-
-@item Displacement Operand
-- s ---- 8 bits
-@item
-- m ---- 16 bits
-@item
-- l ---- 24 bits
+@item Immediate Operand: s
+4 bits.
+
+@item Immediate Operand: m
+16 bits, for movb and movw instructions.
+
+@item Immediate Operand: m
+20 bits, movd instructions.
+
+@item Immediate Operand: l
+32 bits.
+
+@item Absolute Operand: s
+Illegal specifier for this operand.
+
+@item Absolute Operand: m
+20 bits, movd instructions.
+
+@item Displacement Operand: s
+8 bits.
+
+@item Displacement Operand: m
+16 bits.
+
+@item Displacement Operand: l
+24 bits.
+
@end table
For example:
diff --git a/binutils-2.21.1/gas/doc/c-mips.texi b/binutils-2.21.1/gas/doc/c-mips.texi
index 715091e..1250c1e 100644
--- a/binutils-2.21.1/gas/doc/c-mips.texi
+++ binutils-2.21.1/gas/doc/c-mips.texi
@@ -220,7 +220,7 @@ the @samp{mad} and @samp{madu} instruction, and to not schedule @samp{nop}
instructions around accesses to the @samp{HI} and @samp{LO} registers.
@samp{-no-m4650} turns off this option.
-@itemx -m3900
+@item -m3900
@itemx -no-m3900
@itemx -m4100
@itemx -no-m4100
diff --git a/binutils-2.21.1/gas/doc/c-score.texi b/binutils-2.21.1/gas/doc/c-score.texi
index 0820115..a5b570f 100644
--- a/binutils-2.21.1/gas/doc/c-score.texi
+++ binutils-2.21.1/gas/doc/c-score.texi
@@ -36,7 +36,7 @@ implicitly with the @code{gp} register. The default value is 8.
@item -EB
Assemble code for a big-endian cpu
-@itemx -EL
+@item -EL
Assemble code for a little-endian cpu
@item -FIXDD
@@ -48,13 +48,13 @@ Assemble code for no warning message for fix data dependency
@item -SCORE5
Assemble code for target is SCORE5
-@itemx -SCORE5U
+@item -SCORE5U
Assemble code for target is SCORE5U
-@itemx -SCORE7
+@item -SCORE7
Assemble code for target is SCORE7, this is default setting
-@itemx -SCORE3
+@item -SCORE3
Assemble code for target is SCORE3
@item -march=score7
diff --git a/binutils-2.21.1/gas/doc/c-tic54x.texi b/binutils-2.21.1/gas/doc/c-tic54x.texi
index 4cfb440..899b49d 100644
--- a/binutils-2.21.1/gas/doc/c-tic54x.texi
+++ binutils-2.21.1/gas/doc/c-tic54x.texi
@@ -108,7 +108,7 @@ In this example, x is replaced with SYM2; SYM2 is replaced with SYM1, and SYM1
is replaced with x. At this point, x has already been encountered
and the substitution stops.
-@smallexample @code
+@smallexample
.asg "x",SYM1
.asg "SYM1",SYM2
.asg "SYM2",x
@@ -125,14 +125,14 @@ Substitution may be forced in situations where replacement might be
ambiguous by placing colons on either side of the subsym. The following
code:
-@smallexample @code
+@smallexample
.eval "10",x
LAB:X: add #x, a
@end smallexample
When assembled becomes:
-@smallexample @code
+@smallexample
LAB10 add #10, a
@end smallexample
@@ -308,7 +308,7 @@ The @code{LDX} pseudo-op is provided for loading the extended addressing bits
of a label or address. For example, if an address @code{_label} resides
in extended program memory, the value of @code{_label} may be loaded as
follows:
-@smallexample @code
+@smallexample
ldx #_label,16,a ; loads extended bits of _label
or #_label,a ; loads lower 16 bits of _label
bacc a ; full address is in accumulator A
@@ -325,7 +325,7 @@ follows:
@cindex @code{align} directive, TIC54X
@cindex @code{even} directive, TIC54X
@item .align [@var{size}]
-@itemx .even
+@item .even
Align the section program counter on the next boundary, based on
@var{size}. @var{size} may be any power of 2. @code{.even} is
equivalent to @code{.align} with a @var{size} of 2.
@@ -344,7 +344,7 @@ Assign @var{name} the string @var{string}. String replacement is
performed on @var{string} before assignment.
@cindex @code{eval} directive, TIC54X
-@itemx .eval @var{string}, @var{name}
+@item .eval @var{string}, @var{name}
Evaluate the contents of string @var{string} and assign the result as a
string to the subsym @var{name}. String replacement is performed on
@var{string} before assignment.
diff --git a/binutils-2.21.1/include/dis-asm.h b/binutils-2.21.1/include/dis-asm.h
index 63366d9..9f08d4e 100644
--- a/binutils-2.21.1/include/dis-asm.h
+++ binutils-2.21.1/include/dis-asm.h
@@ -227,6 +227,7 @@ extern int print_insn_big_arm (bfd_vma, disassemble_info *);
extern int print_insn_big_mips (bfd_vma, disassemble_info *);
extern int print_insn_big_or32 (bfd_vma, disassemble_info *);
extern int print_insn_big_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_big_riscv (bfd_vma, disassemble_info *);
extern int print_insn_big_score (bfd_vma, disassemble_info *);
extern int print_insn_cr16 (bfd_vma, disassemble_info *);
extern int print_insn_crx (bfd_vma, disassemble_info *);
@@ -253,6 +254,7 @@ extern int print_insn_little_arm (bfd_vma, disassemble_info *);
extern int print_insn_little_mips (bfd_vma, disassemble_info *);
extern int print_insn_little_or32 (bfd_vma, disassemble_info *);
extern int print_insn_little_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_little_riscv (bfd_vma, disassemble_info *);
extern int print_insn_little_score (bfd_vma, disassemble_info *);
extern int print_insn_lm32 (bfd_vma, disassemble_info *);
extern int print_insn_m32c (bfd_vma, disassemble_info *);
diff --git a/binutils-2.21.1/include/elf/common.h b/binutils-2.21.1/include/elf/common.h
index 01c519d..49dafb5 100644
--- a/binutils-2.21.1/include/elf/common.h
+++ binutils-2.21.1/include/elf/common.h
@@ -295,6 +295,7 @@
#define EM_TILEPRO 188 /* Tilera TILEPro multicore architecture family */
#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */
#define EM_CUDA 190 /* NVIDIA CUDA architecture */
+#define EM_RISCV 243 /* RISC-V */
/* If it is necessary to assign new unofficial EM_* values, please pick large
random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision
diff --git a/binutils-2.21.1/include/elf/riscv.h b/binutils-2.21.1/include/elf/riscv.h
new file mode 100644
index 0000000..f455693
--- /dev/null
+++ binutils-2.21.1/include/elf/riscv.h
@@ -0,0 +1,180 @@
+/* RISC-V ELF support for BFD.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2008, 2009, 2010
+ Free Software Foundation, Inc.
+
+ By Andrew Waterman, University of California,
+ <waterman@eecs.berkeley.edu>.
+ Based on MIPS ELF support for BFD, by Ian Lance Taylor.
+
+ 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 holds definitions specific to the RISCV ELF ABI. Note
+ that most of this is not actually implemented by BFD. */
+
+#ifndef _ELF_RISCV_H
+#define _ELF_RISCV_H
+
+#include "elf/reloc-macros.h"
+
+/* Relocation types. */
+START_RELOC_NUMBERS (elf_riscv_reloc_type)
+ RELOC_NUMBER (R_RISCV_NONE, 0)
+ RELOC_NUMBER (R_RISCV_32, 2)
+ RELOC_NUMBER (R_RISCV_REL32, 3)
+ RELOC_NUMBER (R_RISCV_JAL, 4)
+ RELOC_NUMBER (R_RISCV_HI20, 5)
+ RELOC_NUMBER (R_RISCV_LO12_I, 6)
+ RELOC_NUMBER (R_RISCV_LO12_S, 7)
+ RELOC_NUMBER (R_RISCV_PCREL_LO12_I, 8)
+ RELOC_NUMBER (R_RISCV_PCREL_LO12_S, 9)
+ RELOC_NUMBER (R_RISCV_BRANCH, 10)
+ RELOC_NUMBER (R_RISCV_CALL, 11)
+ RELOC_NUMBER (R_RISCV_PCREL_HI20, 12)
+ RELOC_NUMBER (R_RISCV_CALL_PLT, 13)
+ RELOC_NUMBER (R_RISCV_64, 18)
+ RELOC_NUMBER (R_RISCV_GOT_HI20, 22)
+ RELOC_NUMBER (R_RISCV_GOT_LO12, 23)
+ RELOC_NUMBER (R_RISCV_COPY, 24)
+ RELOC_NUMBER (R_RISCV_JUMP_SLOT, 25)
+ /* TLS relocations. */
+ RELOC_NUMBER (R_RISCV_TLS_IE_HI20, 29)
+ RELOC_NUMBER (R_RISCV_TLS_IE_LO12, 30)
+ RELOC_NUMBER (R_RISCV_TLS_IE_ADD, 31)
+ RELOC_NUMBER (R_RISCV_TLS_IE_LO12_I, 32)
+ RELOC_NUMBER (R_RISCV_TLS_IE_LO12_S, 33)
+ RELOC_NUMBER (R_RISCV_TPREL_HI20, 34)
+ RELOC_NUMBER (R_RISCV_TPREL_LO12_I, 35)
+ RELOC_NUMBER (R_RISCV_TPREL_LO12_S, 36)
+ RELOC_NUMBER (R_RISCV_TPREL_ADD, 37)
+ RELOC_NUMBER (R_RISCV_TLS_DTPMOD32, 38)
+ RELOC_NUMBER (R_RISCV_TLS_DTPREL32, 39)
+ RELOC_NUMBER (R_RISCV_TLS_DTPMOD64, 40)
+ RELOC_NUMBER (R_RISCV_TLS_DTPREL64, 41)
+ RELOC_NUMBER (R_RISCV_TLS_TPREL32, 47)
+ RELOC_NUMBER (R_RISCV_TLS_TPREL64, 48)
+ RELOC_NUMBER (R_RISCV_TLS_PCREL_LO12, 50)
+ RELOC_NUMBER (R_RISCV_TLS_GOT_HI20, 51)
+ RELOC_NUMBER (R_RISCV_TLS_GOT_LO12, 52)
+ RELOC_NUMBER (R_RISCV_TLS_GD_HI20, 53)
+ RELOC_NUMBER (R_RISCV_TLS_GD_LO12, 54)
+ RELOC_NUMBER (R_RISCV_GLOB_DAT, 57)
+ RELOC_NUMBER (R_RISCV_ADD32, 58)
+ RELOC_NUMBER (R_RISCV_ADD64, 59)
+ RELOC_NUMBER (R_RISCV_SUB32, 60)
+ RELOC_NUMBER (R_RISCV_SUB64, 61)
+ FAKE_RELOC (R_RISCV_max, 62)
+END_RELOC_NUMBERS (R_RISCV_maxext)
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+/* Custom flag definitions. */
+
+#define EF_RISCV_EXT_MASK 0xffff
+#define EF_RISCV_EXT_SH 16
+#define E_RISCV_EXT_Xcustom 0x0000
+#define E_RISCV_EXT_Xhwacha 0x0001
+#define E_RISCV_EXT_RESERVED 0xffff
+
+#define EF_GET_RISCV_EXT(x) \
+ ((x >> EF_RISCV_EXT_SH) & EF_RISCV_EXT_MASK)
+
+#define EF_SET_RISCV_EXT(x, ext) \
+ do { x |= ((ext & EF_RISCV_EXT_MASK) << EF_RISCV_EXT_SH); } while (0)
+
+#define EF_IS_RISCV_EXT_Xcustom(x) \
+ (EF_GET_RISCV_EXT(x) == E_RISCV_EXT_Xcustom)
+
+/* A mapping from extension names to elf flags */
+
+struct riscv_extension_entry
+{
+ const char* name;
+ unsigned int flag;
+};
+
+static const struct riscv_extension_entry riscv_extension_map[] =
+{
+ {"Xcustom", E_RISCV_EXT_Xcustom},
+ {"Xhwacha", E_RISCV_EXT_Xhwacha},
+};
+
+/* Given an extension name, return an elf flag. */
+
+static inline const char* riscv_elf_flag_to_name(unsigned int flag)
+{
+ unsigned int i;
+
+ for (i=0; i<sizeof(riscv_extension_map)/sizeof(riscv_extension_map[0]); i++)
+ if (riscv_extension_map[i].flag == flag)
+ return riscv_extension_map[i].name;
+
+ return NULL;
+}
+
+/* Given an elf flag, return an extension name. */
+
+static inline unsigned int riscv_elf_name_to_flag(const char* name)
+{
+ unsigned int i;
+
+ for (i=0; i<sizeof(riscv_extension_map)/sizeof(riscv_extension_map[0]); i++)
+ if (strcmp(riscv_extension_map[i].name, name) == 0)
+ return riscv_extension_map[i].flag;
+
+ return E_RISCV_EXT_Xcustom;
+}
+
+/* Processor specific section indices. These sections do not actually
+ exist. Symbols with a st_shndx field corresponding to one of these
+ values have a special meaning. */
+
+/* Defined and allocated common symbol. Value is virtual address. If
+ relocated, alignment must be preserved. */
+#define SHN_RISCV_ACOMMON SHN_LORESERVE
+
+/* Defined and allocated text symbol. Value is virtual address.
+ Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */
+#define SHN_RISCV_TEXT (SHN_LORESERVE + 1)
+
+/* Defined and allocated data symbol. Value is virtual address.
+ Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */
+#define SHN_RISCV_DATA (SHN_LORESERVE + 2)
+
+/* Small common symbol. */
+#define SHN_RISCV_SCOMMON (SHN_LORESERVE + 3)
+
+/* Small undefined symbol. */
+#define SHN_RISCV_SUNDEFINED (SHN_LORESERVE + 4)
+
+/* Get ELf32_xxx struct definitions */
+#include "mips.h"
+
+/* Number of local global offset table entries. */
+#define DT_RISCV_LOCAL_GOTNO 0x70000000
+
+/* Number of entries in the .dynsym section. */
+#define DT_RISCV_SYMTABNO 0x70000001
+
+/* Index of first dynamic symbol in global offset table. */
+#define DT_RISCV_GOTSYM 0x70000002
+
+/* Address of the base of the PLTGOT. */
+#define DT_RISCV_PLTGOT 0x70000003
+
+#endif /* _ELF_RISCV_H */
diff --git a/binutils-2.21.1/include/opcode/riscv-opc.h b/binutils-2.21.1/include/opcode/riscv-opc.h
new file mode 100644
index 0000000..eb29d3e
--- /dev/null
+++ binutils-2.21.1/include/opcode/riscv-opc.h
@@ -0,0 +1,1216 @@
+/* Automatically generated by parse-opcodes */
+#ifndef RISCV_ENCODING_H
+#define RISCV_ENCODING_H
+#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
+#define MASK_CUSTOM3_RD_RS1_RS2 0x707f
+#define MATCH_VLSEGSTWU 0xc00305b
+#define MASK_VLSEGSTWU 0x1e00707f
+#define MATCH_C_LW0 0x12
+#define MASK_C_LW0 0x801f
+#define MATCH_FMV_D_X 0xf2000053
+#define MASK_FMV_D_X 0xfff0707f
+#define MATCH_VLH 0x200205b
+#define MASK_VLH 0xfff0707f
+#define MATCH_C_LI 0x0
+#define MASK_C_LI 0x1f
+#define MATCH_FADD_D 0x2000053
+#define MASK_FADD_D 0xfe00007f
+#define MATCH_C_LD 0x9
+#define MASK_C_LD 0x1f
+#define MATCH_VLD 0x600205b
+#define MASK_VLD 0xfff0707f
+#define MATCH_FADD_S 0x53
+#define MASK_FADD_S 0xfe00007f
+#define MATCH_C_LW 0xa
+#define MASK_C_LW 0x1f
+#define MATCH_VLW 0x400205b
+#define MASK_VLW 0xfff0707f
+#define MATCH_VSSEGSTW 0x400307b
+#define MASK_VSSEGSTW 0x1e00707f
+#define MATCH_UTIDX 0x6077
+#define MASK_UTIDX 0xfffff07f
+#define MATCH_C_FLW 0x14
+#define MASK_C_FLW 0x1f
+#define MATCH_FSUB_D 0xa000053
+#define MASK_FSUB_D 0xfe00007f
+#define MATCH_VSSEGSTD 0x600307b
+#define MASK_VSSEGSTD 0x1e00707f
+#define MATCH_VSSEGSTB 0x307b
+#define MASK_VSSEGSTB 0x1e00707f
+#define MATCH_DIV 0x2004033
+#define MASK_DIV 0xfe00707f
+#define MATCH_FMV_H_X 0xf4000053
+#define MASK_FMV_H_X 0xfff0707f
+#define MATCH_C_FLD 0x15
+#define MASK_C_FLD 0x1f
+#define MATCH_FRRM 0x202073
+#define MASK_FRRM 0xfffff07f
+#define MATCH_VFMSV_S 0x1000202b
+#define MASK_VFMSV_S 0xfff0707f
+#define MATCH_C_LWSP 0x5
+#define MASK_C_LWSP 0x1f
+#define MATCH_FENCE 0xf
+#define MASK_FENCE 0x707f
+#define MATCH_FNMSUB_S 0x4b
+#define MASK_FNMSUB_S 0x600007f
+#define MATCH_FLE_S 0xa0000053
+#define MASK_FLE_S 0xfe00707f
+#define MATCH_FNMSUB_H 0x400004b
+#define MASK_FNMSUB_H 0x600007f
+#define MATCH_FLE_H 0xbc000053
+#define MASK_FLE_H 0xfe00707f
+#define MATCH_FLW 0x2007
+#define MASK_FLW 0x707f
+#define MATCH_VSETVL 0x600b
+#define MASK_VSETVL 0xfff0707f
+#define MATCH_VFMSV_D 0x1200202b
+#define MASK_VFMSV_D 0xfff0707f
+#define MATCH_FLE_D 0xa2000053
+#define MASK_FLE_D 0xfe00707f
+#define MATCH_FENCE_I 0x100f
+#define MASK_FENCE_I 0x707f
+#define MATCH_FNMSUB_D 0x200004b
+#define MASK_FNMSUB_D 0x600007f
+#define MATCH_ADDW 0x3b
+#define MASK_ADDW 0xfe00707f
+#define MATCH_XOR 0x4033
+#define MASK_XOR 0xfe00707f
+#define MATCH_SUB 0x40000033
+#define MASK_SUB 0xfe00707f
+#define MATCH_VSSTW 0x400307b
+#define MASK_VSSTW 0xfe00707f
+#define MATCH_VSSTH 0x200307b
+#define MASK_VSSTH 0xfe00707f
+#define MATCH_SC_W 0x1800202f
+#define MASK_SC_W 0xf800707f
+#define MATCH_VSSTB 0x307b
+#define MASK_VSSTB 0xfe00707f
+#define MATCH_VSSTD 0x600307b
+#define MASK_VSSTD 0xfe00707f
+#define MATCH_ADDI 0x13
+#define MASK_ADDI 0x707f
+#define MATCH_RDTIMEH 0xc8102073
+#define MASK_RDTIMEH 0xfffff07f
+#define MATCH_MULH 0x2001033
+#define MASK_MULH 0xfe00707f
+#define MATCH_CSRRSI 0x6073
+#define MASK_CSRRSI 0x707f
+#define MATCH_FCVT_D_WU 0xd2100053
+#define MASK_FCVT_D_WU 0xfff0007f
+#define MATCH_MULW 0x200003b
+#define MASK_MULW 0xfe00707f
+#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b
+#define MASK_CUSTOM1_RD_RS1_RS2 0x707f
+#define MATCH_VENQIMM1 0xc00302b
+#define MASK_VENQIMM1 0xfe007fff
+#define MATCH_VENQIMM2 0xe00302b
+#define MASK_VENQIMM2 0xfe007fff
+#define MATCH_RDINSTRET 0xc0202073
+#define MASK_RDINSTRET 0xfffff07f
+#define MATCH_C_SWSP 0x8
+#define MASK_C_SWSP 0x1f
+#define MATCH_VLSTW 0x400305b
+#define MASK_VLSTW 0xfe00707f
+#define MATCH_VLSTH 0x200305b
+#define MASK_VLSTH 0xfe00707f
+#define MATCH_VLSTB 0x305b
+#define MASK_VLSTB 0xfe00707f
+#define MATCH_VLSTD 0x600305b
+#define MASK_VLSTD 0xfe00707f
+#define MATCH_ANDI 0x7013
+#define MASK_ANDI 0x707f
+#define MATCH_FMV_X_S 0xe0000053
+#define MASK_FMV_X_S 0xfff0707f
+#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b
+#define MASK_CUSTOM0_RD_RS1_RS2 0x707f
+#define MATCH_FNMADD_S 0x4f
+#define MASK_FNMADD_S 0x600007f
+#define MATCH_LWU 0x6003
+#define MASK_LWU 0x707f
+#define MATCH_CUSTOM0_RS1 0x200b
+#define MASK_CUSTOM0_RS1 0x707f
+#define MATCH_VLSEGSTBU 0x800305b
+#define MASK_VLSEGSTBU 0x1e00707f
+#define MATCH_FNMADD_D 0x200004f
+#define MASK_FNMADD_D 0x600007f
+#define MATCH_FCVT_W_S 0xc0000053
+#define MASK_FCVT_W_S 0xfff0007f
+#define MATCH_C_SRAI 0x1019
+#define MASK_C_SRAI 0x1c1f
+#define MATCH_MULHSU 0x2002033
+#define MASK_MULHSU 0xfe00707f
+#define MATCH_FCVT_D_LU 0xd2300053
+#define MASK_FCVT_D_LU 0xfff0007f
+#define MATCH_FCVT_W_D 0xc2000053
+#define MASK_FCVT_W_D 0xfff0007f
+#define MATCH_FSUB_H 0xc000053
+#define MASK_FSUB_H 0xfe00007f
+#define MATCH_DIVUW 0x200503b
+#define MASK_DIVUW 0xfe00707f
+#define MATCH_SLTI 0x2013
+#define MASK_SLTI 0x707f
+#define MATCH_VLSTBU 0x800305b
+#define MASK_VLSTBU 0xfe00707f
+#define MATCH_SLTU 0x3033
+#define MASK_SLTU 0xfe00707f
+#define MATCH_FLH 0x1007
+#define MASK_FLH 0x707f
+#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b
+#define MASK_CUSTOM2_RD_RS1_RS2 0x707f
+#define MATCH_FLD 0x3007
+#define MASK_FLD 0x707f
+#define MATCH_FSUB_S 0x8000053
+#define MASK_FSUB_S 0xfe00007f
+#define MATCH_FCVT_H_LU 0x6c000053
+#define MASK_FCVT_H_LU 0xfff0007f
+#define MATCH_CUSTOM0 0xb
+#define MASK_CUSTOM0 0x707f
+#define MATCH_CUSTOM1 0x2b
+#define MASK_CUSTOM1 0x707f
+#define MATCH_CUSTOM2 0x5b
+#define MASK_CUSTOM2 0x707f
+#define MATCH_CUSTOM3 0x7b
+#define MASK_CUSTOM3 0x707f
+#define MATCH_VXCPTSAVE 0x302b
+#define MASK_VXCPTSAVE 0xfff07fff
+#define MATCH_VMSV 0x200202b
+#define MASK_VMSV 0xfff0707f
+#define MATCH_FCVT_LU_S 0xc0300053
+#define MASK_FCVT_LU_S 0xfff0007f
+#define MATCH_AUIPC 0x17
+#define MASK_AUIPC 0x7f
+#define MATCH_FRFLAGS 0x102073
+#define MASK_FRFLAGS 0xfffff07f
+#define MATCH_FCVT_LU_D 0xc2300053
+#define MASK_FCVT_LU_D 0xfff0007f
+#define MATCH_CSRRWI 0x5073
+#define MASK_CSRRWI 0x707f
+#define MATCH_FADD_H 0x4000053
+#define MASK_FADD_H 0xfe00007f
+#define MATCH_FSQRT_S 0x58000053
+#define MASK_FSQRT_S 0xfff0007f
+#define MATCH_VXCPTKILL 0x400302b
+#define MASK_VXCPTKILL 0xffffffff
+#define MATCH_STOP 0x5077
+#define MASK_STOP 0xffffffff
+#define MATCH_FSGNJN_S 0x20001053
+#define MASK_FSGNJN_S 0xfe00707f
+#define MATCH_FSGNJN_H 0x34000053
+#define MASK_FSGNJN_H 0xfe00707f
+#define MATCH_FSQRT_D 0x5a000053
+#define MASK_FSQRT_D 0xfff0007f
+#define MATCH_XORI 0x4013
+#define MASK_XORI 0x707f
+#define MATCH_DIVU 0x2005033
+#define MASK_DIVU 0xfe00707f
+#define MATCH_FSGNJN_D 0x22001053
+#define MASK_FSGNJN_D 0xfe00707f
+#define MATCH_FSQRT_H 0x24000053
+#define MASK_FSQRT_H 0xfff0007f
+#define MATCH_VSSEGSTH 0x200307b
+#define MASK_VSSEGSTH 0x1e00707f
+#define MATCH_SW 0x2023
+#define MASK_SW 0x707f
+#define MATCH_VLSTWU 0xc00305b
+#define MASK_VLSTWU 0xfe00707f
+#define MATCH_VFSSEGW 0x1400207b
+#define MASK_VFSSEGW 0x1ff0707f
+#define MATCH_LHU 0x5003
+#define MASK_LHU 0x707f
+#define MATCH_SH 0x1023
+#define MASK_SH 0x707f
+#define MATCH_FMSUB_H 0x4000047
+#define MASK_FMSUB_H 0x600007f
+#define MATCH_VXCPTAUX 0x200402b
+#define MASK_VXCPTAUX 0xfffff07f
+#define MATCH_FMSUB_D 0x2000047
+#define MASK_FMSUB_D 0x600007f
+#define MATCH_VFSSEGD 0x1600207b
+#define MASK_VFSSEGD 0x1ff0707f
+#define MATCH_VLSEGHU 0xa00205b
+#define MASK_VLSEGHU 0x1ff0707f
+#define MATCH_MOVN 0x2007077
+#define MASK_MOVN 0xfe00707f
+#define MATCH_CUSTOM1_RS1 0x202b
+#define MASK_CUSTOM1_RS1 0x707f
+#define MATCH_VLSTHU 0xa00305b
+#define MASK_VLSTHU 0xfe00707f
+#define MATCH_MOVZ 0x7077
+#define MASK_MOVZ 0xfe00707f
+#define MATCH_CSRRW 0x1073
+#define MASK_CSRRW 0x707f
+#define MATCH_LD 0x3003
+#define MASK_LD 0x707f
+#define MATCH_LB 0x3
+#define MASK_LB 0x707f
+#define MATCH_VLWU 0xc00205b
+#define MASK_VLWU 0xfff0707f
+#define MATCH_LH 0x1003
+#define MASK_LH 0x707f
+#define MATCH_LW 0x2003
+#define MASK_LW 0x707f
+#define MATCH_CSRRC 0x3073
+#define MASK_CSRRC 0x707f
+#define MATCH_FCVT_LU_H 0x4c000053
+#define MASK_FCVT_LU_H 0xfff0007f
+#define MATCH_FCVT_S_D 0x40100053
+#define MASK_FCVT_S_D 0xfff0007f
+#define MATCH_BGEU 0x7063
+#define MASK_BGEU 0x707f
+#define MATCH_VFLSTD 0x1600305b
+#define MASK_VFLSTD 0xfe00707f
+#define MATCH_FCVT_S_L 0xd0200053
+#define MASK_FCVT_S_L 0xfff0007f
+#define MATCH_FCVT_S_H 0x84000053
+#define MASK_FCVT_S_H 0xfff0007f
+#define MATCH_FSCSR 0x301073
+#define MASK_FSCSR 0xfff0707f
+#define MATCH_FCVT_S_W 0xd0000053
+#define MASK_FCVT_S_W 0xfff0007f
+#define MATCH_VFLSTW 0x1400305b
+#define MASK_VFLSTW 0xfe00707f
+#define MATCH_VXCPTEVAC 0x600302b
+#define MASK_VXCPTEVAC 0xfff07fff
+#define MATCH_AMOMINU_D 0xc000302f
+#define MASK_AMOMINU_D 0xf800707f
+#define MATCH_FSFLAGS 0x101073
+#define MASK_FSFLAGS 0xfff0707f
+#define MATCH_SRLI 0x5013
+#define MASK_SRLI 0xfc00707f
+#define MATCH_C_SRLI 0x819
+#define MASK_C_SRLI 0x1c1f
+#define MATCH_AMOMINU_W 0xc000202f
+#define MASK_AMOMINU_W 0xf800707f
+#define MATCH_SRLW 0x503b
+#define MASK_SRLW 0xfe00707f
+#define MATCH_VFLSEGW 0x1400205b
+#define MASK_VFLSEGW 0x1ff0707f
+#define MATCH_C_LD0 0x8012
+#define MASK_C_LD0 0x801f
+#define MATCH_VLSEGBU 0x800205b
+#define MASK_VLSEGBU 0x1ff0707f
+#define MATCH_JALR 0x67
+#define MASK_JALR 0x707f
+#define MATCH_BLT 0x4063
+#define MASK_BLT 0x707f
+#define MATCH_CUSTOM2_RD_RS1 0x605b
+#define MASK_CUSTOM2_RD_RS1 0x707f
+#define MATCH_FCLASS_S 0xe0001053
+#define MASK_FCLASS_S 0xfff0707f
+#define MATCH_REM 0x2006033
+#define MASK_REM 0xfe00707f
+#define MATCH_FCLASS_D 0xe2001053
+#define MASK_FCLASS_D 0xfff0707f
+#define MATCH_FMUL_S 0x10000053
+#define MASK_FMUL_S 0xfe00007f
+#define MATCH_RDCYCLEH 0xc8002073
+#define MASK_RDCYCLEH 0xfffff07f
+#define MATCH_VLSEGSTHU 0xa00305b
+#define MASK_VLSEGSTHU 0x1e00707f
+#define MATCH_FMUL_D 0x12000053
+#define MASK_FMUL_D 0xfe00007f
+#define MATCH_ORI 0x6013
+#define MASK_ORI 0x707f
+#define MATCH_FMUL_H 0x14000053
+#define MASK_FMUL_H 0xfe00007f
+#define MATCH_VFLSEGD 0x1600205b
+#define MASK_VFLSEGD 0x1ff0707f
+#define MATCH_FEQ_S 0xa0002053
+#define MASK_FEQ_S 0xfe00707f
+#define MATCH_FSGNJX_D 0x22002053
+#define MASK_FSGNJX_D 0xfe00707f
+#define MATCH_SRAIW 0x4000501b
+#define MASK_SRAIW 0xfe00707f
+#define MATCH_FSGNJX_H 0x3c000053
+#define MASK_FSGNJX_H 0xfe00707f
+#define MATCH_FSGNJX_S 0x20002053
+#define MASK_FSGNJX_S 0xfe00707f
+#define MATCH_FEQ_D 0xa2002053
+#define MASK_FEQ_D 0xfe00707f
+#define MATCH_CUSTOM1_RD_RS1 0x602b
+#define MASK_CUSTOM1_RD_RS1 0x707f
+#define MATCH_FEQ_H 0xac000053
+#define MASK_FEQ_H 0xfe00707f
+#define MATCH_AMOMAXU_D 0xe000302f
+#define MASK_AMOMAXU_D 0xf800707f
+#define MATCH_DIVW 0x200403b
+#define MASK_DIVW 0xfe00707f
+#define MATCH_AMOMAXU_W 0xe000202f
+#define MASK_AMOMAXU_W 0xf800707f
+#define MATCH_SRAI_RV32 0x40005013
+#define MASK_SRAI_RV32 0xfe00707f
+#define MATCH_C_SRLI32 0xc19
+#define MASK_C_SRLI32 0x1c1f
+#define MATCH_VFSSTW 0x1400307b
+#define MASK_VFSSTW 0xfe00707f
+#define MATCH_CUSTOM0_RD 0x400b
+#define MASK_CUSTOM0_RD 0x707f
+#define MATCH_C_BEQ 0x10
+#define MASK_C_BEQ 0x1f
+#define MATCH_VFSSTD 0x1600307b
+#define MASK_VFSSTD 0xfe00707f
+#define MATCH_CUSTOM3_RD_RS1 0x607b
+#define MASK_CUSTOM3_RD_RS1 0x707f
+#define MATCH_LR_D 0x1000302f
+#define MASK_LR_D 0xf9f0707f
+#define MATCH_LR_W 0x1000202f
+#define MASK_LR_W 0xf9f0707f
+#define MATCH_FCVT_H_WU 0x7c000053
+#define MASK_FCVT_H_WU 0xfff0007f
+#define MATCH_VMVV 0x200002b
+#define MASK_VMVV 0xfff0707f
+#define MATCH_SLLW 0x103b
+#define MASK_SLLW 0xfe00707f
+#define MATCH_SLLI 0x1013
+#define MASK_SLLI 0xfc00707f
+#define MATCH_BEQ 0x63
+#define MASK_BEQ 0x707f
+#define MATCH_AND 0x7033
+#define MASK_AND 0xfe00707f
+#define MATCH_LBU 0x4003
+#define MASK_LBU 0x707f
+#define MATCH_FSGNJ_S 0x20000053
+#define MASK_FSGNJ_S 0xfe00707f
+#define MATCH_FMSUB_S 0x47
+#define MASK_FMSUB_S 0x600007f
+#define MATCH_C_SUB3 0x11c
+#define MASK_C_SUB3 0x31f
+#define MATCH_FSGNJ_H 0x2c000053
+#define MASK_FSGNJ_H 0xfe00707f
+#define MATCH_VLB 0x205b
+#define MASK_VLB 0xfff0707f
+#define MATCH_C_ADDIW 0x1d
+#define MASK_C_ADDIW 0x1f
+#define MATCH_CUSTOM3_RS1_RS2 0x307b
+#define MASK_CUSTOM3_RS1_RS2 0x707f
+#define MATCH_FSGNJ_D 0x22000053
+#define MASK_FSGNJ_D 0xfe00707f
+#define MATCH_VLSEGWU 0xc00205b
+#define MASK_VLSEGWU 0x1ff0707f
+#define MATCH_FCVT_S_WU 0xd0100053
+#define MASK_FCVT_S_WU 0xfff0007f
+#define MATCH_CUSTOM3_RS1 0x207b
+#define MASK_CUSTOM3_RS1 0x707f
+#define MATCH_SC_D 0x1800302f
+#define MASK_SC_D 0xf800707f
+#define MATCH_VFSW 0x1400207b
+#define MASK_VFSW 0xfff0707f
+#define MATCH_AMOSWAP_D 0x800302f
+#define MASK_AMOSWAP_D 0xf800707f
+#define MATCH_SB 0x23
+#define MASK_SB 0x707f
+#define MATCH_AMOSWAP_W 0x800202f
+#define MASK_AMOSWAP_W 0xf800707f
+#define MATCH_VFSD 0x1600207b
+#define MASK_VFSD 0xfff0707f
+#define MATCH_CUSTOM2_RS1 0x205b
+#define MASK_CUSTOM2_RS1 0x707f
+#define MATCH_SD 0x3023
+#define MASK_SD 0x707f
+#define MATCH_FMV_S_X 0xf0000053
+#define MASK_FMV_S_X 0xfff0707f
+#define MATCH_REMUW 0x200703b
+#define MASK_REMUW 0xfe00707f
+#define MATCH_JAL 0x6f
+#define MASK_JAL 0x7f
+#define MATCH_C_FSD 0x18
+#define MASK_C_FSD 0x1f
+#define MATCH_RDCYCLE 0xc0002073
+#define MASK_RDCYCLE 0xfffff07f
+#define MATCH_C_BNE 0x11
+#define MASK_C_BNE 0x1f
+#define MATCH_C_ADD 0x1a
+#define MASK_C_ADD 0x801f
+#define MATCH_VXCPTCAUSE 0x402b
+#define MASK_VXCPTCAUSE 0xfffff07f
+#define MATCH_VGETCFG 0x400b
+#define MASK_VGETCFG 0xfffff07f
+#define MATCH_LUI 0x37
+#define MASK_LUI 0x7f
+#define MATCH_VSETCFG 0x200b
+#define MASK_VSETCFG 0x7fff
+#define MATCH_C_SDSP 0x6
+#define MASK_C_SDSP 0x1f
+#define MATCH_C_LDSP 0x4
+#define MASK_C_LDSP 0x1f
+#define MATCH_FNMADD_H 0x400004f
+#define MASK_FNMADD_H 0x600007f
+#define MATCH_CUSTOM0_RS1_RS2 0x300b
+#define MASK_CUSTOM0_RS1_RS2 0x707f
+#define MATCH_SLLI_RV32 0x1013
+#define MASK_SLLI_RV32 0xfe00707f
+#define MATCH_MUL 0x2000033
+#define MASK_MUL 0xfe00707f
+#define MATCH_CSRRCI 0x7073
+#define MASK_CSRRCI 0x707f
+#define MATCH_C_SRAI32 0x1419
+#define MASK_C_SRAI32 0x1c1f
+#define MATCH_FLT_H 0xb4000053
+#define MASK_FLT_H 0xfe00707f
+#define MATCH_SRAI 0x40005013
+#define MASK_SRAI 0xfc00707f
+#define MATCH_AMOAND_D 0x6000302f
+#define MASK_AMOAND_D 0xf800707f
+#define MATCH_FLT_D 0xa2001053
+#define MASK_FLT_D 0xfe00707f
+#define MATCH_SRAW 0x4000503b
+#define MASK_SRAW 0xfe00707f
+#define MATCH_CSRRS 0x2073
+#define MASK_CSRRS 0x707f
+#define MATCH_FLT_S 0xa0001053
+#define MASK_FLT_S 0xfe00707f
+#define MATCH_ADDIW 0x1b
+#define MASK_ADDIW 0x707f
+#define MATCH_AMOAND_W 0x6000202f
+#define MASK_AMOAND_W 0xf800707f
+#define MATCH_CUSTOM2_RD 0x405b
+#define MASK_CUSTOM2_RD 0x707f
+#define MATCH_FCVT_WU_D 0xc2100053
+#define MASK_FCVT_WU_D 0xfff0007f
+#define MATCH_AMOXOR_W 0x2000202f
+#define MASK_AMOXOR_W 0xf800707f
+#define MATCH_FCVT_D_L 0xd2200053
+#define MASK_FCVT_D_L 0xfff0007f
+#define MATCH_FCVT_WU_H 0x5c000053
+#define MASK_FCVT_WU_H 0xfff0007f
+#define MATCH_C_SLLI 0x19
+#define MASK_C_SLLI 0x1c1f
+#define MATCH_AMOXOR_D 0x2000302f
+#define MASK_AMOXOR_D 0xf800707f
+#define MATCH_FCVT_WU_S 0xc0100053
+#define MASK_FCVT_WU_S 0xfff0007f
+#define MATCH_CUSTOM3_RD 0x407b
+#define MASK_CUSTOM3_RD 0x707f
+#define MATCH_FMAX_H 0xcc000053
+#define MASK_FMAX_H 0xfe00707f
+#define MATCH_VENQCNT 0x1000302b
+#define MASK_VENQCNT 0xfe007fff
+#define MATCH_VLBU 0x800205b
+#define MASK_VLBU 0xfff0707f
+#define MATCH_VLHU 0xa00205b
+#define MASK_VLHU 0xfff0707f
+#define MATCH_C_SW 0xd
+#define MASK_C_SW 0x1f
+#define MATCH_C_SD 0xc
+#define MASK_C_SD 0x1f
+#define MATCH_C_OR3 0x21c
+#define MASK_C_OR3 0x31f
+#define MATCH_C_AND3 0x31c
+#define MASK_C_AND3 0x31f
+#define MATCH_VFSSEGSTW 0x1400307b
+#define MASK_VFSSEGSTW 0x1e00707f
+#define MATCH_SLT 0x2033
+#define MASK_SLT 0xfe00707f
+#define MATCH_AMOOR_D 0x4000302f
+#define MASK_AMOOR_D 0xf800707f
+#define MATCH_REMU 0x2007033
+#define MASK_REMU 0xfe00707f
+#define MATCH_REMW 0x200603b
+#define MASK_REMW 0xfe00707f
+#define MATCH_SLL 0x1033
+#define MASK_SLL 0xfe00707f
+#define MATCH_VFSSEGSTD 0x1600307b
+#define MASK_VFSSEGSTD 0x1e00707f
+#define MATCH_AMOOR_W 0x4000202f
+#define MASK_AMOOR_W 0xf800707f
+#define MATCH_CUSTOM2_RS1_RS2 0x305b
+#define MASK_CUSTOM2_RS1_RS2 0x707f
+#define MATCH_VF 0x10202b
+#define MASK_VF 0x1f0707f
+#define MATCH_VFMVV 0x1000002b
+#define MASK_VFMVV 0xfff0707f
+#define MATCH_VFLSEGSTW 0x1400305b
+#define MASK_VFLSEGSTW 0x1e00707f
+#define MATCH_VXCPTRESTORE 0x200302b
+#define MASK_VXCPTRESTORE 0xfff07fff
+#define MATCH_VXCPTHOLD 0x800302b
+#define MASK_VXCPTHOLD 0xffffffff
+#define MATCH_SLTIU 0x3013
+#define MASK_SLTIU 0x707f
+#define MATCH_VFLSEGSTD 0x1600305b
+#define MASK_VFLSEGSTD 0x1e00707f
+#define MATCH_VFLD 0x1600205b
+#define MASK_VFLD 0xfff0707f
+#define MATCH_FMADD_S 0x43
+#define MASK_FMADD_S 0x600007f
+#define MATCH_VFLW 0x1400205b
+#define MASK_VFLW 0xfff0707f
+#define MATCH_FMADD_D 0x2000043
+#define MASK_FMADD_D 0x600007f
+#define MATCH_FMADD_H 0x4000043
+#define MASK_FMADD_H 0x600007f
+#define MATCH_SRET 0x80000073
+#define MASK_SRET 0xffffffff
+#define MATCH_VSSEGW 0x400207b
+#define MASK_VSSEGW 0x1ff0707f
+#define MATCH_CUSTOM0_RD_RS1 0x600b
+#define MASK_CUSTOM0_RD_RS1 0x707f
+#define MATCH_VSSEGH 0x200207b
+#define MASK_VSSEGH 0x1ff0707f
+#define MATCH_FRCSR 0x302073
+#define MASK_FRCSR 0xfffff07f
+#define MATCH_VSSEGD 0x600207b
+#define MASK_VSSEGD 0x1ff0707f
+#define MATCH_VSSEGB 0x207b
+#define MASK_VSSEGB 0x1ff0707f
+#define MATCH_FMIN_H 0xc4000053
+#define MASK_FMIN_H 0xfe00707f
+#define MATCH_FMIN_D 0x2a000053
+#define MASK_FMIN_D 0xfe00707f
+#define MATCH_BLTU 0x6063
+#define MASK_BLTU 0x707f
+#define MATCH_FMIN_S 0x28000053
+#define MASK_FMIN_S 0xfe00707f
+#define MATCH_SRLI_RV32 0x5013
+#define MASK_SRLI_RV32 0xfe00707f
+#define MATCH_SLLIW 0x101b
+#define MASK_SLLIW 0xfe00707f
+#define MATCH_FMAX_S 0x28001053
+#define MASK_FMAX_S 0xfe00707f
+#define MATCH_FCVT_D_H 0x8c000053
+#define MASK_FCVT_D_H 0xfff0007f
+#define MATCH_FCVT_D_W 0xd2000053
+#define MASK_FCVT_D_W 0xfff0007f
+#define MATCH_ADD 0x33
+#define MASK_ADD 0xfe00707f
+#define MATCH_FCVT_D_S 0x42000053
+#define MASK_FCVT_D_S 0xfff0007f
+#define MATCH_FMAX_D 0x2a001053
+#define MASK_FMAX_D 0xfe00707f
+#define MATCH_BNE 0x1063
+#define MASK_BNE 0x707f
+#define MATCH_CUSTOM1_RD 0x402b
+#define MASK_CUSTOM1_RD 0x707f
+#define MATCH_FSRM 0x201073
+#define MASK_FSRM 0xfff0707f
+#define MATCH_FDIV_D 0x1a000053
+#define MASK_FDIV_D 0xfe00007f
+#define MATCH_VSW 0x400207b
+#define MASK_VSW 0xfff0707f
+#define MATCH_FCVT_L_S 0xc0200053
+#define MASK_FCVT_L_S 0xfff0007f
+#define MATCH_FDIV_H 0x1c000053
+#define MASK_FDIV_H 0xfe00007f
+#define MATCH_VSB 0x207b
+#define MASK_VSB 0xfff0707f
+#define MATCH_FDIV_S 0x18000053
+#define MASK_FDIV_S 0xfe00007f
+#define MATCH_FSRMI 0x205073
+#define MASK_FSRMI 0xfff0707f
+#define MATCH_FCVT_L_H 0x44000053
+#define MASK_FCVT_L_H 0xfff0007f
+#define MATCH_VSH 0x200207b
+#define MASK_VSH 0xfff0707f
+#define MATCH_FCVT_L_D 0xc2200053
+#define MASK_FCVT_L_D 0xfff0007f
+#define MATCH_FCVT_H_S 0x90000053
+#define MASK_FCVT_H_S 0xfff0007f
+#define MATCH_SCALL 0x73
+#define MASK_SCALL 0xffffffff
+#define MATCH_FSFLAGSI 0x105073
+#define MASK_FSFLAGSI 0xfff0707f
+#define MATCH_FCVT_H_W 0x74000053
+#define MASK_FCVT_H_W 0xfff0007f
+#define MATCH_FCVT_H_L 0x64000053
+#define MASK_FCVT_H_L 0xfff0007f
+#define MATCH_SRLIW 0x501b
+#define MASK_SRLIW 0xfe00707f
+#define MATCH_FCVT_S_LU 0xd0300053
+#define MASK_FCVT_S_LU 0xfff0007f
+#define MATCH_FCVT_H_D 0x92000053
+#define MASK_FCVT_H_D 0xfff0007f
+#define MATCH_SBREAK 0x100073
+#define MASK_SBREAK 0xffffffff
+#define MATCH_RDINSTRETH 0xc8202073
+#define MASK_RDINSTRETH 0xfffff07f
+#define MATCH_SRA 0x40005033
+#define MASK_SRA 0xfe00707f
+#define MATCH_BGE 0x5063
+#define MASK_BGE 0x707f
+#define MATCH_SRL 0x5033
+#define MASK_SRL 0xfe00707f
+#define MATCH_VENQCMD 0xa00302b
+#define MASK_VENQCMD 0xfe007fff
+#define MATCH_OR 0x6033
+#define MASK_OR 0xfe00707f
+#define MATCH_SUBW 0x4000003b
+#define MASK_SUBW 0xfe00707f
+#define MATCH_FMV_X_D 0xe2000053
+#define MASK_FMV_X_D 0xfff0707f
+#define MATCH_RDTIME 0xc0102073
+#define MASK_RDTIME 0xfffff07f
+#define MATCH_AMOADD_D 0x302f
+#define MASK_AMOADD_D 0xf800707f
+#define MATCH_AMOMAX_W 0xa000202f
+#define MASK_AMOMAX_W 0xf800707f
+#define MATCH_C_MOVE 0x2
+#define MASK_C_MOVE 0x801f
+#define MATCH_FMOVN 0x6007077
+#define MASK_FMOVN 0xfe00707f
+#define MATCH_C_FSW 0x16
+#define MASK_C_FSW 0x1f
+#define MATCH_AMOADD_W 0x202f
+#define MASK_AMOADD_W 0xf800707f
+#define MATCH_AMOMAX_D 0xa000302f
+#define MASK_AMOMAX_D 0xf800707f
+#define MATCH_FMOVZ 0x4007077
+#define MASK_FMOVZ 0xfe00707f
+#define MATCH_CUSTOM1_RS1_RS2 0x302b
+#define MASK_CUSTOM1_RS1_RS2 0x707f
+#define MATCH_FMV_X_H 0xe4000053
+#define MASK_FMV_X_H 0xfff0707f
+#define MATCH_VSD 0x600207b
+#define MASK_VSD 0xfff0707f
+#define MATCH_VLSEGSTW 0x400305b
+#define MASK_VLSEGSTW 0x1e00707f
+#define MATCH_C_ADDI 0x1
+#define MASK_C_ADDI 0x1f
+#define MATCH_C_SLLIW 0x1819
+#define MASK_C_SLLIW 0x1c1f
+#define MATCH_VLSEGSTB 0x305b
+#define MASK_VLSEGSTB 0x1e00707f
+#define MATCH_VLSEGSTD 0x600305b
+#define MASK_VLSEGSTD 0x1e00707f
+#define MATCH_VLSEGSTH 0x200305b
+#define MASK_VLSEGSTH 0x1e00707f
+#define MATCH_MULHU 0x2003033
+#define MASK_MULHU 0xfe00707f
+#define MATCH_AMOMIN_W 0x8000202f
+#define MASK_AMOMIN_W 0xf800707f
+#define MATCH_C_SLLI32 0x419
+#define MASK_C_SLLI32 0x1c1f
+#define MATCH_C_ADD3 0x1c
+#define MASK_C_ADD3 0x31f
+#define MATCH_VGETVL 0x200400b
+#define MASK_VGETVL 0xfffff07f
+#define MATCH_AMOMIN_D 0x8000302f
+#define MASK_AMOMIN_D 0xf800707f
+#define MATCH_FCVT_W_H 0x54000053
+#define MASK_FCVT_W_H 0xfff0007f
+#define MATCH_VLSEGB 0x205b
+#define MASK_VLSEGB 0x1ff0707f
+#define MATCH_FSD 0x3027
+#define MASK_FSD 0x707f
+#define MATCH_VLSEGD 0x600205b
+#define MASK_VLSEGD 0x1ff0707f
+#define MATCH_FSH 0x1027
+#define MASK_FSH 0x707f
+#define MATCH_VLSEGH 0x200205b
+#define MASK_VLSEGH 0x1ff0707f
+#define MATCH_C_SUB 0x801a
+#define MASK_C_SUB 0x801f
+#define MATCH_VLSEGW 0x400205b
+#define MASK_VLSEGW 0x1ff0707f
+#define MATCH_FSW 0x2027
+#define MASK_FSW 0x707f
+#define MATCH_C_J 0x8002
+#define MASK_C_J 0x801f
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#define CSR_STATS 0xc0
+#define CSR_SUP0 0x500
+#define CSR_SUP1 0x501
+#define CSR_EPC 0x502
+#define CSR_BADVADDR 0x503
+#define CSR_PTBR 0x504
+#define CSR_ASID 0x505
+#define CSR_COUNT 0x506
+#define CSR_COMPARE 0x507
+#define CSR_EVEC 0x508
+#define CSR_CAUSE 0x509
+#define CSR_STATUS 0x50a
+#define CSR_HARTID 0x50b
+#define CSR_IMPL 0x50c
+#define CSR_FATC 0x50d
+#define CSR_SEND_IPI 0x50e
+#define CSR_CLEAR_IPI 0x50f
+#define CSR_RESET 0x51d
+#define CSR_TOHOST 0x51e
+#define CSR_FROMHOST 0x51f
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_UARCH0 0xcc0
+#define CSR_UARCH1 0xcc1
+#define CSR_UARCH2 0xcc2
+#define CSR_UARCH3 0xcc3
+#define CSR_UARCH4 0xcc4
+#define CSR_UARCH5 0xcc5
+#define CSR_UARCH6 0xcc6
+#define CSR_UARCH7 0xcc7
+#define CSR_UARCH8 0xcc8
+#define CSR_UARCH9 0xcc9
+#define CSR_UARCH10 0xcca
+#define CSR_UARCH11 0xccb
+#define CSR_UARCH12 0xccc
+#define CSR_UARCH13 0xccd
+#define CSR_UARCH14 0xcce
+#define CSR_UARCH15 0xccf
+#define CSR_COUNTH 0x586
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CAUSE_MISALIGNED_FETCH 0x0
+#define CAUSE_FAULT_FETCH 0x1
+#define CAUSE_ILLEGAL_INSTRUCTION 0x2
+#define CAUSE_PRIVILEGED_INSTRUCTION 0x3
+#define CAUSE_FP_DISABLED 0x4
+#define CAUSE_SYSCALL 0x6
+#define CAUSE_BREAKPOINT 0x7
+#define CAUSE_MISALIGNED_LOAD 0x8
+#define CAUSE_MISALIGNED_STORE 0x9
+#define CAUSE_FAULT_LOAD 0xa
+#define CAUSE_FAULT_STORE 0xb
+#define CAUSE_ACCELERATOR_DISABLED 0xc
+#endif
+#ifdef DECLARE_INSN
+DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
+DECLARE_INSN(vlsegstwu, MATCH_VLSEGSTWU, MASK_VLSEGSTWU)
+DECLARE_INSN(c_lw0, MATCH_C_LW0, MASK_C_LW0)
+DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X)
+DECLARE_INSN(vlh, MATCH_VLH, MASK_VLH)
+DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
+DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(vld, MATCH_VLD, MASK_VLD)
+DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S)
+DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
+DECLARE_INSN(vlw, MATCH_VLW, MASK_VLW)
+DECLARE_INSN(vssegstw, MATCH_VSSEGSTW, MASK_VSSEGSTW)
+DECLARE_INSN(utidx, MATCH_UTIDX, MASK_UTIDX)
+DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
+DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D)
+DECLARE_INSN(vssegstd, MATCH_VSSEGSTD, MASK_VSSEGSTD)
+DECLARE_INSN(vssegstb, MATCH_VSSEGSTB, MASK_VSSEGSTB)
+DECLARE_INSN(div, MATCH_DIV, MASK_DIV)
+DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X)
+DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
+DECLARE_INSN(frrm, MATCH_FRRM, MASK_FRRM)
+DECLARE_INSN(vfmsv_s, MATCH_VFMSV_S, MASK_VFMSV_S)
+DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
+DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE)
+DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S)
+DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S)
+DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H)
+DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H)
+DECLARE_INSN(flw, MATCH_FLW, MASK_FLW)
+DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL)
+DECLARE_INSN(vfmsv_d, MATCH_VFMSV_D, MASK_VFMSV_D)
+DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D)
+DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I)
+DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D)
+DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW)
+DECLARE_INSN(xor, MATCH_XOR, MASK_XOR)
+DECLARE_INSN(sub, MATCH_SUB, MASK_SUB)
+DECLARE_INSN(vsstw, MATCH_VSSTW, MASK_VSSTW)
+DECLARE_INSN(vssth, MATCH_VSSTH, MASK_VSSTH)
+DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W)
+DECLARE_INSN(vsstb, MATCH_VSSTB, MASK_VSSTB)
+DECLARE_INSN(vsstd, MATCH_VSSTD, MASK_VSSTD)
+DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
+DECLARE_INSN(rdtimeh, MATCH_RDTIMEH, MASK_RDTIMEH)
+DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH)
+DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI)
+DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
+DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW)
+DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2)
+DECLARE_INSN(venqimm1, MATCH_VENQIMM1, MASK_VENQIMM1)
+DECLARE_INSN(venqimm2, MATCH_VENQIMM2, MASK_VENQIMM2)
+DECLARE_INSN(rdinstret, MATCH_RDINSTRET, MASK_RDINSTRET)
+DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
+DECLARE_INSN(vlstw, MATCH_VLSTW, MASK_VLSTW)
+DECLARE_INSN(vlsth, MATCH_VLSTH, MASK_VLSTH)
+DECLARE_INSN(vlstb, MATCH_VLSTB, MASK_VLSTB)
+DECLARE_INSN(vlstd, MATCH_VLSTD, MASK_VLSTD)
+DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI)
+DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S)
+DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2)
+DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S)
+DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU)
+DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1)
+DECLARE_INSN(vlsegstbu, MATCH_VLSEGSTBU, MASK_VLSEGSTBU)
+DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D)
+DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S)
+DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI)
+DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU)
+DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU)
+DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D)
+DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H)
+DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW)
+DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI)
+DECLARE_INSN(vlstbu, MATCH_VLSTBU, MASK_VLSTBU)
+DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU)
+DECLARE_INSN(flh, MATCH_FLH, MASK_FLH)
+DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2)
+DECLARE_INSN(fld, MATCH_FLD, MASK_FLD)
+DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S)
+DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU)
+DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0)
+DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1)
+DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2)
+DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3)
+DECLARE_INSN(vxcptsave, MATCH_VXCPTSAVE, MASK_VXCPTSAVE)
+DECLARE_INSN(vmsv, MATCH_VMSV, MASK_VMSV)
+DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S)
+DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC)
+DECLARE_INSN(frflags, MATCH_FRFLAGS, MASK_FRFLAGS)
+DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D)
+DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI)
+DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H)
+DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S)
+DECLARE_INSN(vxcptkill, MATCH_VXCPTKILL, MASK_VXCPTKILL)
+DECLARE_INSN(stop, MATCH_STOP, MASK_STOP)
+DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S)
+DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H)
+DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D)
+DECLARE_INSN(xori, MATCH_XORI, MASK_XORI)
+DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU)
+DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D)
+DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H)
+DECLARE_INSN(vssegsth, MATCH_VSSEGSTH, MASK_VSSEGSTH)
+DECLARE_INSN(sw, MATCH_SW, MASK_SW)
+DECLARE_INSN(vlstwu, MATCH_VLSTWU, MASK_VLSTWU)
+DECLARE_INSN(vfssegw, MATCH_VFSSEGW, MASK_VFSSEGW)
+DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU)
+DECLARE_INSN(sh, MATCH_SH, MASK_SH)
+DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H)
+DECLARE_INSN(vxcptaux, MATCH_VXCPTAUX, MASK_VXCPTAUX)
+DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D)
+DECLARE_INSN(vfssegd, MATCH_VFSSEGD, MASK_VFSSEGD)
+DECLARE_INSN(vlseghu, MATCH_VLSEGHU, MASK_VLSEGHU)
+DECLARE_INSN(movn, MATCH_MOVN, MASK_MOVN)
+DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1)
+DECLARE_INSN(vlsthu, MATCH_VLSTHU, MASK_VLSTHU)
+DECLARE_INSN(movz, MATCH_MOVZ, MASK_MOVZ)
+DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW)
+DECLARE_INSN(ld, MATCH_LD, MASK_LD)
+DECLARE_INSN(lb, MATCH_LB, MASK_LB)
+DECLARE_INSN(vlwu, MATCH_VLWU, MASK_VLWU)
+DECLARE_INSN(lh, MATCH_LH, MASK_LH)
+DECLARE_INSN(lw, MATCH_LW, MASK_LW)
+DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC)
+DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H)
+DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D)
+DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
+DECLARE_INSN(vflstd, MATCH_VFLSTD, MASK_VFLSTD)
+DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L)
+DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H)
+DECLARE_INSN(fscsr, MATCH_FSCSR, MASK_FSCSR)
+DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W)
+DECLARE_INSN(vflstw, MATCH_VFLSTW, MASK_VFLSTW)
+DECLARE_INSN(vxcptevac, MATCH_VXCPTEVAC, MASK_VXCPTEVAC)
+DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D)
+DECLARE_INSN(fsflags, MATCH_FSFLAGS, MASK_FSFLAGS)
+DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI)
+DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI)
+DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W)
+DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW)
+DECLARE_INSN(vflsegw, MATCH_VFLSEGW, MASK_VFLSEGW)
+DECLARE_INSN(c_ld0, MATCH_C_LD0, MASK_C_LD0)
+DECLARE_INSN(vlsegbu, MATCH_VLSEGBU, MASK_VLSEGBU)
+DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
+DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
+DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1)
+DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
+DECLARE_INSN(rem, MATCH_REM, MASK_REM)
+DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D)
+DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S)
+DECLARE_INSN(rdcycleh, MATCH_RDCYCLEH, MASK_RDCYCLEH)
+DECLARE_INSN(vlsegsthu, MATCH_VLSEGSTHU, MASK_VLSEGSTHU)
+DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D)
+DECLARE_INSN(ori, MATCH_ORI, MASK_ORI)
+DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H)
+DECLARE_INSN(vflsegd, MATCH_VFLSEGD, MASK_VFLSEGD)
+DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S)
+DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D)
+DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW)
+DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H)
+DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S)
+DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D)
+DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1)
+DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H)
+DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D)
+DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW)
+DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W)
+DECLARE_INSN(srai_rv32, MATCH_SRAI_RV32, MASK_SRAI_RV32)
+DECLARE_INSN(c_srli32, MATCH_C_SRLI32, MASK_C_SRLI32)
+DECLARE_INSN(vfsstw, MATCH_VFSSTW, MASK_VFSSTW)
+DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD)
+DECLARE_INSN(c_beq, MATCH_C_BEQ, MASK_C_BEQ)
+DECLARE_INSN(vfsstd, MATCH_VFSSTD, MASK_VFSSTD)
+DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
+DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D)
+DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W)
+DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU)
+DECLARE_INSN(vmvv, MATCH_VMVV, MASK_VMVV)
+DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW)
+DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI)
+DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
+DECLARE_INSN(and, MATCH_AND, MASK_AND)
+DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU)
+DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S)
+DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S)
+DECLARE_INSN(c_sub3, MATCH_C_SUB3, MASK_C_SUB3)
+DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H)
+DECLARE_INSN(vlb, MATCH_VLB, MASK_VLB)
+DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
+DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
+DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D)
+DECLARE_INSN(vlsegwu, MATCH_VLSEGWU, MASK_VLSEGWU)
+DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU)
+DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1)
+DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D)
+DECLARE_INSN(vfsw, MATCH_VFSW, MASK_VFSW)
+DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D)
+DECLARE_INSN(sb, MATCH_SB, MASK_SB)
+DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W)
+DECLARE_INSN(vfsd, MATCH_VFSD, MASK_VFSD)
+DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1)
+DECLARE_INSN(sd, MATCH_SD, MASK_SD)
+DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
+DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW)
+DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
+DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD)
+DECLARE_INSN(rdcycle, MATCH_RDCYCLE, MASK_RDCYCLE)
+DECLARE_INSN(c_bne, MATCH_C_BNE, MASK_C_BNE)
+DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
+DECLARE_INSN(vxcptcause, MATCH_VXCPTCAUSE, MASK_VXCPTCAUSE)
+DECLARE_INSN(vgetcfg, MATCH_VGETCFG, MASK_VGETCFG)
+DECLARE_INSN(lui, MATCH_LUI, MASK_LUI)
+DECLARE_INSN(vsetcfg, MATCH_VSETCFG, MASK_VSETCFG)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
+DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H)
+DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2)
+DECLARE_INSN(slli_rv32, MATCH_SLLI_RV32, MASK_SLLI_RV32)
+DECLARE_INSN(mul, MATCH_MUL, MASK_MUL)
+DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI)
+DECLARE_INSN(c_srai32, MATCH_C_SRAI32, MASK_C_SRAI32)
+DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H)
+DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI)
+DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D)
+DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D)
+DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW)
+DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS)
+DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S)
+DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW)
+DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W)
+DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD)
+DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D)
+DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W)
+DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L)
+DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H)
+DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
+DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D)
+DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S)
+DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
+DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H)
+DECLARE_INSN(venqcnt, MATCH_VENQCNT, MASK_VENQCNT)
+DECLARE_INSN(vlbu, MATCH_VLBU, MASK_VLBU)
+DECLARE_INSN(vlhu, MATCH_VLHU, MASK_VLHU)
+DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_or3, MATCH_C_OR3, MASK_C_OR3)
+DECLARE_INSN(c_and3, MATCH_C_AND3, MASK_C_AND3)
+DECLARE_INSN(vfssegstw, MATCH_VFSSEGSTW, MASK_VFSSEGSTW)
+DECLARE_INSN(slt, MATCH_SLT, MASK_SLT)
+DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D)
+DECLARE_INSN(remu, MATCH_REMU, MASK_REMU)
+DECLARE_INSN(remw, MATCH_REMW, MASK_REMW)
+DECLARE_INSN(sll, MATCH_SLL, MASK_SLL)
+DECLARE_INSN(vfssegstd, MATCH_VFSSEGSTD, MASK_VFSSEGSTD)
+DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W)
+DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2)
+DECLARE_INSN(vf, MATCH_VF, MASK_VF)
+DECLARE_INSN(vfmvv, MATCH_VFMVV, MASK_VFMVV)
+DECLARE_INSN(vflsegstw, MATCH_VFLSEGSTW, MASK_VFLSEGSTW)
+DECLARE_INSN(vxcptrestore, MATCH_VXCPTRESTORE, MASK_VXCPTRESTORE)
+DECLARE_INSN(vxcpthold, MATCH_VXCPTHOLD, MASK_VXCPTHOLD)
+DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU)
+DECLARE_INSN(vflsegstd, MATCH_VFLSEGSTD, MASK_VFLSEGSTD)
+DECLARE_INSN(vfld, MATCH_VFLD, MASK_VFLD)
+DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S)
+DECLARE_INSN(vflw, MATCH_VFLW, MASK_VFLW)
+DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D)
+DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H)
+DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
+DECLARE_INSN(vssegw, MATCH_VSSEGW, MASK_VSSEGW)
+DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1)
+DECLARE_INSN(vssegh, MATCH_VSSEGH, MASK_VSSEGH)
+DECLARE_INSN(frcsr, MATCH_FRCSR, MASK_FRCSR)
+DECLARE_INSN(vssegd, MATCH_VSSEGD, MASK_VSSEGD)
+DECLARE_INSN(vssegb, MATCH_VSSEGB, MASK_VSSEGB)
+DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H)
+DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D)
+DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
+DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S)
+DECLARE_INSN(srli_rv32, MATCH_SRLI_RV32, MASK_SRLI_RV32)
+DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW)
+DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S)
+DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H)
+DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W)
+DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
+DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S)
+DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D)
+DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
+DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD)
+DECLARE_INSN(fsrm, MATCH_FSRM, MASK_FSRM)
+DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D)
+DECLARE_INSN(vsw, MATCH_VSW, MASK_VSW)
+DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S)
+DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H)
+DECLARE_INSN(vsb, MATCH_VSB, MASK_VSB)
+DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S)
+DECLARE_INSN(fsrmi, MATCH_FSRMI, MASK_FSRMI)
+DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H)
+DECLARE_INSN(vsh, MATCH_VSH, MASK_VSH)
+DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D)
+DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S)
+DECLARE_INSN(scall, MATCH_SCALL, MASK_SCALL)
+DECLARE_INSN(fsflagsi, MATCH_FSFLAGSI, MASK_FSFLAGSI)
+DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W)
+DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L)
+DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW)
+DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU)
+DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D)
+DECLARE_INSN(sbreak, MATCH_SBREAK, MASK_SBREAK)
+DECLARE_INSN(rdinstreth, MATCH_RDINSTRETH, MASK_RDINSTRETH)
+DECLARE_INSN(sra, MATCH_SRA, MASK_SRA)
+DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
+DECLARE_INSN(srl, MATCH_SRL, MASK_SRL)
+DECLARE_INSN(venqcmd, MATCH_VENQCMD, MASK_VENQCMD)
+DECLARE_INSN(or, MATCH_OR, MASK_OR)
+DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW)
+DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D)
+DECLARE_INSN(rdtime, MATCH_RDTIME, MASK_RDTIME)
+DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D)
+DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W)
+DECLARE_INSN(c_move, MATCH_C_MOVE, MASK_C_MOVE)
+DECLARE_INSN(fmovn, MATCH_FMOVN, MASK_FMOVN)
+DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
+DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W)
+DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D)
+DECLARE_INSN(fmovz, MATCH_FMOVZ, MASK_FMOVZ)
+DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2)
+DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H)
+DECLARE_INSN(vsd, MATCH_VSD, MASK_VSD)
+DECLARE_INSN(vlsegstw, MATCH_VLSEGSTW, MASK_VLSEGSTW)
+DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_slliw, MATCH_C_SLLIW, MASK_C_SLLIW)
+DECLARE_INSN(vlsegstb, MATCH_VLSEGSTB, MASK_VLSEGSTB)
+DECLARE_INSN(vlsegstd, MATCH_VLSEGSTD, MASK_VLSEGSTD)
+DECLARE_INSN(vlsegsth, MATCH_VLSEGSTH, MASK_VLSEGSTH)
+DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU)
+DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W)
+DECLARE_INSN(c_slli32, MATCH_C_SLLI32, MASK_C_SLLI32)
+DECLARE_INSN(c_add3, MATCH_C_ADD3, MASK_C_ADD3)
+DECLARE_INSN(vgetvl, MATCH_VGETVL, MASK_VGETVL)
+DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D)
+DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H)
+DECLARE_INSN(vlsegb, MATCH_VLSEGB, MASK_VLSEGB)
+DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD)
+DECLARE_INSN(vlsegd, MATCH_VLSEGD, MASK_VLSEGD)
+DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH)
+DECLARE_INSN(vlsegh, MATCH_VLSEGH, MASK_VLSEGH)
+DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB)
+DECLARE_INSN(vlsegw, MATCH_VLSEGW, MASK_VLSEGW)
+DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW)
+DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
+#endif
+#ifdef DECLARE_CSR
+DECLARE_CSR(fflags, CSR_FFLAGS)
+DECLARE_CSR(frm, CSR_FRM)
+DECLARE_CSR(fcsr, CSR_FCSR)
+DECLARE_CSR(stats, CSR_STATS)
+DECLARE_CSR(sup0, CSR_SUP0)
+DECLARE_CSR(sup1, CSR_SUP1)
+DECLARE_CSR(epc, CSR_EPC)
+DECLARE_CSR(badvaddr, CSR_BADVADDR)
+DECLARE_CSR(ptbr, CSR_PTBR)
+DECLARE_CSR(asid, CSR_ASID)
+DECLARE_CSR(count, CSR_COUNT)
+DECLARE_CSR(compare, CSR_COMPARE)
+DECLARE_CSR(evec, CSR_EVEC)
+DECLARE_CSR(cause, CSR_CAUSE)
+DECLARE_CSR(status, CSR_STATUS)
+DECLARE_CSR(hartid, CSR_HARTID)
+DECLARE_CSR(impl, CSR_IMPL)
+DECLARE_CSR(fatc, CSR_FATC)
+DECLARE_CSR(send_ipi, CSR_SEND_IPI)
+DECLARE_CSR(clear_ipi, CSR_CLEAR_IPI)
+DECLARE_CSR(reset, CSR_RESET)
+DECLARE_CSR(tohost, CSR_TOHOST)
+DECLARE_CSR(fromhost, CSR_FROMHOST)
+DECLARE_CSR(cycle, CSR_CYCLE)
+DECLARE_CSR(time, CSR_TIME)
+DECLARE_CSR(instret, CSR_INSTRET)
+DECLARE_CSR(uarch0, CSR_UARCH0)
+DECLARE_CSR(uarch1, CSR_UARCH1)
+DECLARE_CSR(uarch2, CSR_UARCH2)
+DECLARE_CSR(uarch3, CSR_UARCH3)
+DECLARE_CSR(uarch4, CSR_UARCH4)
+DECLARE_CSR(uarch5, CSR_UARCH5)
+DECLARE_CSR(uarch6, CSR_UARCH6)
+DECLARE_CSR(uarch7, CSR_UARCH7)
+DECLARE_CSR(uarch8, CSR_UARCH8)
+DECLARE_CSR(uarch9, CSR_UARCH9)
+DECLARE_CSR(uarch10, CSR_UARCH10)
+DECLARE_CSR(uarch11, CSR_UARCH11)
+DECLARE_CSR(uarch12, CSR_UARCH12)
+DECLARE_CSR(uarch13, CSR_UARCH13)
+DECLARE_CSR(uarch14, CSR_UARCH14)
+DECLARE_CSR(uarch15, CSR_UARCH15)
+DECLARE_CSR(counth, CSR_COUNTH)
+DECLARE_CSR(cycleh, CSR_CYCLEH)
+DECLARE_CSR(timeh, CSR_TIMEH)
+DECLARE_CSR(instreth, CSR_INSTRETH)
+#endif
+#ifdef DECLARE_CAUSE
+DECLARE_CAUSE("fflags", CAUSE_FFLAGS)
+DECLARE_CAUSE("frm", CAUSE_FRM)
+DECLARE_CAUSE("fcsr", CAUSE_FCSR)
+DECLARE_CAUSE("stats", CAUSE_STATS)
+DECLARE_CAUSE("sup0", CAUSE_SUP0)
+DECLARE_CAUSE("sup1", CAUSE_SUP1)
+DECLARE_CAUSE("epc", CAUSE_EPC)
+DECLARE_CAUSE("badvaddr", CAUSE_BADVADDR)
+DECLARE_CAUSE("ptbr", CAUSE_PTBR)
+DECLARE_CAUSE("asid", CAUSE_ASID)
+DECLARE_CAUSE("count", CAUSE_COUNT)
+DECLARE_CAUSE("compare", CAUSE_COMPARE)
+DECLARE_CAUSE("evec", CAUSE_EVEC)
+DECLARE_CAUSE("cause", CAUSE_CAUSE)
+DECLARE_CAUSE("status", CAUSE_STATUS)
+DECLARE_CAUSE("hartid", CAUSE_HARTID)
+DECLARE_CAUSE("impl", CAUSE_IMPL)
+DECLARE_CAUSE("fatc", CAUSE_FATC)
+DECLARE_CAUSE("send_ipi", CAUSE_SEND_IPI)
+DECLARE_CAUSE("clear_ipi", CAUSE_CLEAR_IPI)
+DECLARE_CAUSE("reset", CAUSE_RESET)
+DECLARE_CAUSE("tohost", CAUSE_TOHOST)
+DECLARE_CAUSE("fromhost", CAUSE_FROMHOST)
+DECLARE_CAUSE("cycle", CAUSE_CYCLE)
+DECLARE_CAUSE("time", CAUSE_TIME)
+DECLARE_CAUSE("instret", CAUSE_INSTRET)
+DECLARE_CAUSE("uarch0", CAUSE_UARCH0)
+DECLARE_CAUSE("uarch1", CAUSE_UARCH1)
+DECLARE_CAUSE("uarch2", CAUSE_UARCH2)
+DECLARE_CAUSE("uarch3", CAUSE_UARCH3)
+DECLARE_CAUSE("uarch4", CAUSE_UARCH4)
+DECLARE_CAUSE("uarch5", CAUSE_UARCH5)
+DECLARE_CAUSE("uarch6", CAUSE_UARCH6)
+DECLARE_CAUSE("uarch7", CAUSE_UARCH7)
+DECLARE_CAUSE("uarch8", CAUSE_UARCH8)
+DECLARE_CAUSE("uarch9", CAUSE_UARCH9)
+DECLARE_CAUSE("uarch10", CAUSE_UARCH10)
+DECLARE_CAUSE("uarch11", CAUSE_UARCH11)
+DECLARE_CAUSE("uarch12", CAUSE_UARCH12)
+DECLARE_CAUSE("uarch13", CAUSE_UARCH13)
+DECLARE_CAUSE("uarch14", CAUSE_UARCH14)
+DECLARE_CAUSE("uarch15", CAUSE_UARCH15)
+DECLARE_CAUSE("counth", CAUSE_COUNTH)
+DECLARE_CAUSE("cycleh", CAUSE_CYCLEH)
+DECLARE_CAUSE("timeh", CAUSE_TIMEH)
+DECLARE_CAUSE("instreth", CAUSE_INSTRETH)
+#endif
diff --git a/binutils-2.21.1/include/opcode/riscv.h b/binutils-2.21.1/include/opcode/riscv.h
new file mode 100644
index 0000000..d228175
--- /dev/null
+++ binutils-2.21.1/include/opcode/riscv.h
@@ -0,0 +1,326 @@
+/* riscv.h. RISC-V opcode list for GDB, the GNU debugger.
+ Copyright 2011
+ Free Software Foundation, Inc.
+ Contributed by Andrew Waterman
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _RISCV_H_
+#define _RISCV_H_
+
+#include "riscv-opc.h"
+#include <stdlib.h>
+#include <stdint.h>
+
+/* RVC fields */
+
+#define OP_MASK_COP 0x1f
+#define OP_SH_COP 0
+#define OP_MASK_CRD 0x1f
+#define OP_SH_CRD 5
+#define OP_MASK_CRS2 0x1f
+#define OP_SH_CRS2 5
+#define OP_MASK_CRS1 0x1f
+#define OP_SH_CRS1 10
+#define OP_MASK_CRDS 0x7
+#define OP_SH_CRDS 13
+#define OP_MASK_CRS2S 0x7
+#define OP_SH_CRS2S 13
+#define OP_MASK_CRS2BS 0x7
+#define OP_SH_CRS2BS 5
+#define OP_MASK_CRS1S 0x7
+#define OP_SH_CRS1S 10
+#define OP_MASK_CIMM6 0x3f
+#define OP_SH_CIMM6 10
+#define OP_MASK_CIMM5 0x1f
+#define OP_SH_CIMM5 5
+#define OP_MASK_CIMM10 0x3ff
+#define OP_SH_CIMM10 5
+
+static const char rvc_rs1_regmap[8] = { 20, 21, 2, 3, 4, 5, 6, 7 };
+#define rvc_rd_regmap rvc_rs1_regmap
+#define rvc_rs2b_regmap rvc_rs1_regmap
+static const char rvc_rs2_regmap[8] = { 20, 21, 2, 3, 4, 5, 6, 0 };
+
+typedef uint64_t insn_t;
+
+static inline unsigned int riscv_insn_length (insn_t insn)
+{
+ if ((insn & 0x3) != 3) /* RVC */
+ return 2;
+ if ((insn & 0x1f) != 0x1f) /* base ISA and extensions in 32-bit space */
+ return 4;
+ if ((insn & 0x3f) == 0x1f) /* 48-bit extensions */
+ return 6;
+ if ((insn & 0x7f) == 0x3f) /* 64-bit extensions */
+ return 8;
+ /* longer instructions not supported at the moment */
+ return 2;
+}
+
+static const char * const riscv_rm[8] = {
+ "rne", "rtz", "rdn", "rup", "rmm", 0, 0, "dyn"
+};
+static const char* const riscv_pred_succ[16] = {
+ 0, "w", "r", "rw", "o", "ow", "or", "orw",
+ "i", "iw", "ir", "irw", "io", "iow", "ior", "iorw",
+};
+
+#define RVC_JUMP_BITS 10
+#define RVC_JUMP_ALIGN_BITS 1
+#define RVC_JUMP_ALIGN (1 << RVC_JUMP_ALIGN_BITS)
+#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RVC_JUMP_ALIGN)
+
+#define RVC_BRANCH_BITS 5
+#define RVC_BRANCH_ALIGN_BITS RVC_JUMP_ALIGN_BITS
+#define RVC_BRANCH_ALIGN (1 << RVC_BRANCH_ALIGN_BITS)
+#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RVC_BRANCH_ALIGN)
+
+#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1))
+#define RV_IMM_SIGN(x) (-(((x) >> 31) & 1))
+
+#define EXTRACT_ITYPE_IMM(x) \
+ (RV_X(x, 20, 12) | (RV_IMM_SIGN(x) << 12))
+#define EXTRACT_STYPE_IMM(x) \
+ (RV_X(x, 7, 5) | (RV_X(x, 25, 7) << 5) | (RV_IMM_SIGN(x) << 12))
+#define EXTRACT_SBTYPE_IMM(x) \
+ ((RV_X(x, 8, 4) << 1) | (RV_X(x, 25, 6) << 5) | (RV_X(x, 7, 1) << 11) | (RV_IMM_SIGN(x) << 12))
+#define EXTRACT_UTYPE_IMM(x) \
+ (RV_X(x, 12, 20) | (RV_IMM_SIGN(x) << 20))
+#define EXTRACT_UJTYPE_IMM(x) \
+ ((RV_X(x, 21, 10) << 1) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 12, 8) << 12) | (RV_IMM_SIGN(x) << 20))
+
+#define ENCODE_ITYPE_IMM(x) \
+ (RV_X(x, 0, 12) << 20)
+#define ENCODE_STYPE_IMM(x) \
+ ((RV_X(x, 0, 5) << 7) | (RV_X(x, 5, 7) << 25))
+#define ENCODE_SBTYPE_IMM(x) \
+ ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
+#define ENCODE_UTYPE_IMM(x) \
+ (RV_X(x, 0, 20) << 12)
+#define ENCODE_UJTYPE_IMM(x) \
+ ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
+
+#define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
+#define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
+#define VALID_SBTYPE_IMM(x) (EXTRACT_SBTYPE_IMM(ENCODE_SBTYPE_IMM(x)) == (x))
+#define VALID_UTYPE_IMM(x) (EXTRACT_UTYPE_IMM(ENCODE_UTYPE_IMM(x)) == (x))
+#define VALID_UJTYPE_IMM(x) (EXTRACT_UJTYPE_IMM(ENCODE_UJTYPE_IMM(x)) == (x))
+
+#define RISCV_RTYPE(insn, rd, rs1, rs2) \
+ ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
+#define RISCV_ITYPE(insn, rd, rs1, imm) \
+ ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ENCODE_ITYPE_IMM(imm))
+#define RISCV_STYPE(insn, rs1, rs2, imm) \
+ ((MATCH_ ## insn) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2) | ENCODE_STYPE_IMM(imm))
+#define RISCV_SBTYPE(insn, rs1, rs2, target) \
+ ((MATCH_ ## insn) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2) | ENCODE_SBTYPE_IMM(target))
+#define RISCV_UTYPE(insn, rd, bigimm) \
+ ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ENCODE_UTYPE_IMM(bigimm))
+#define RISCV_UJTYPE(insn, rd, target) \
+ ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ENCODE_UJTYPE_IMM(target))
+
+#define RISCV_NOP RISCV_ITYPE(ADDI, 0, 0, 0)
+
+#define RISCV_CONST_HIGH_PART(VALUE) \
+ (((VALUE) + (RISCV_IMM_REACH/2)) & ~(RISCV_IMM_REACH-1))
+#define RISCV_CONST_LOW_PART(VALUE) ((VALUE) - RISCV_CONST_HIGH_PART (VALUE))
+#define RISCV_LUI_HIGH_PART(VALUE) (RISCV_CONST_HIGH_PART(VALUE) >> RISCV_IMM_BITS)
+#define RISCV_PCREL_HIGH_PART(VALUE, PC) RISCV_LUI_HIGH_PART((VALUE) - (PC))
+#define RISCV_PCREL_LOW_PART(VALUE, PC) RISCV_CONST_LOW_PART((VALUE) - (PC))
+
+/* RV fields */
+
+#define OP_MASK_OP 0x7f
+#define OP_SH_OP 0
+#define OP_MASK_RS2 0x1f
+#define OP_SH_RS2 20
+#define OP_MASK_RS1 0x1f
+#define OP_SH_RS1 15
+#define OP_MASK_RS3 0x1f
+#define OP_SH_RS3 27
+#define OP_MASK_RD 0x1f
+#define OP_SH_RD 7
+#define OP_MASK_SHAMT 0x3f
+#define OP_SH_SHAMT 20
+#define OP_MASK_SHAMTW 0x1f
+#define OP_SH_SHAMTW 20
+#define OP_MASK_RM 0x7
+#define OP_SH_RM 12
+#define OP_MASK_PRED 0xf
+#define OP_SH_PRED 24
+#define OP_MASK_SUCC 0xf
+#define OP_SH_SUCC 20
+#define OP_MASK_AQ 0x1
+#define OP_SH_AQ 26
+#define OP_MASK_RL 0x1
+#define OP_SH_RL 25
+
+#define OP_MASK_VRD 0x1f
+#define OP_SH_VRD 7
+#define OP_MASK_VRS 0x1f
+#define OP_SH_VRS 15
+#define OP_MASK_VRT 0x1f
+#define OP_SH_VRT 20
+#define OP_MASK_VRR 0x1f
+#define OP_SH_VRR 27
+
+#define OP_MASK_VFD 0x1f
+#define OP_SH_VFD 7
+#define OP_MASK_VFS 0x1f
+#define OP_SH_VFS 15
+#define OP_MASK_VFT 0x1f
+#define OP_SH_VFT 20
+#define OP_MASK_VFR 0x1f
+#define OP_SH_VFR 27
+
+#define OP_MASK_IMMNGPR 0x3f
+#define OP_SH_IMMNGPR 20
+#define OP_MASK_IMMNFPR 0x3f
+#define OP_SH_IMMNFPR 26
+#define OP_MASK_IMMSEGNELM 0x7
+#define OP_SH_IMMSEGNELM 29
+#define OP_MASK_CUSTOM_IMM 0x7f
+#define OP_SH_CUSTOM_IMM 25
+#define OP_MASK_CSR 0xfff
+#define OP_SH_CSR 20
+
+#define LINK_REG 1
+#define TP_REG 15
+#define GP_REG 31
+
+#define RISCV_JUMP_BITS RISCV_BIGIMM_BITS
+#define RISCV_JUMP_ALIGN_BITS 1
+#define RISCV_JUMP_ALIGN (1 << RISCV_JUMP_ALIGN_BITS)
+#define RISCV_JUMP_REACH ((1ULL<<RISCV_JUMP_BITS)*RISCV_JUMP_ALIGN)
+
+#define RISCV_IMM_BITS 12
+#define RISCV_BIGIMM_BITS (32-RISCV_IMM_BITS)
+#define RISCV_IMM_REACH (1LL<<RISCV_IMM_BITS)
+#define RISCV_BIGIMM_REACH (1LL<<RISCV_BIGIMM_BITS)
+#define RISCV_BRANCH_BITS RISCV_IMM_BITS
+#define RISCV_BRANCH_ALIGN_BITS RISCV_JUMP_ALIGN_BITS
+#define RISCV_BRANCH_ALIGN (1 << RISCV_BRANCH_ALIGN_BITS)
+#define RISCV_BRANCH_REACH (RISCV_IMM_REACH*RISCV_BRANCH_ALIGN)
+
+/* This structure holds information for a particular instruction. */
+
+struct riscv_opcode
+{
+ /* The name of the instruction. */
+ const char *name;
+ /* The ISA subset name (I, M, A, F, D, Xextension). */
+ const char *subset;
+ /* A string describing the arguments for this instruction. */
+ const char *args;
+ /* The basic opcode for the instruction. When assembling, this
+ opcode is modified by the arguments to produce the actual opcode
+ that is used. If pinfo is INSN_MACRO, then this is 0. */
+ insn_t match;
+ /* If pinfo is not INSN_MACRO, then this is a bit mask for the
+ relevant portions of the opcode when disassembling. If the
+ actual opcode anded with the match field equals the opcode field,
+ then we have found the correct instruction. If pinfo is
+ INSN_MACRO, then this field is the macro identifier. */
+ insn_t mask;
+ /* A function to determine if a word corresponds to this instruction.
+ Usually, this computes ((word & mask) == match). */
+ int (*match_func)(const struct riscv_opcode *op, insn_t word);
+ /* For a macro, this is INSN_MACRO. Otherwise, it is a collection
+ of bits describing the instruction, notably any relevant hazard
+ information. */
+ unsigned long pinfo;
+};
+
+#define INSN_WRITE_GPR_D 0x00000001
+#define INSN_WRITE_GPR_RA 0x00000004
+#define INSN_WRITE_FPR_D 0x00000008
+#define INSN_READ_GPR_S 0x00000040
+#define INSN_READ_GPR_T 0x00000080
+#define INSN_READ_FPR_S 0x00000100
+#define INSN_READ_FPR_T 0x00000200
+#define INSN_READ_FPR_R 0x00000400
+/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */
+#define INSN_ALIAS 0x00001000
+/* Instruction is actually a macro. It should be ignored by the
+ disassembler, and requires special treatment by the assembler. */
+#define INSN_MACRO 0xffffffff
+
+/* These are the bits which may be set in the pinfo2 field of an
+ instruction. */
+
+/* MIPS ISA defines, use instead of hardcoding ISA level. */
+
+#define ISA_UNKNOWN 0 /* Gas internal use. */
+#define ISA_RV32 1
+#define ISA_RV64 2
+
+/* This is a list of macro expanded instructions.
+
+ _I appended means immediate
+ _A appended means address
+ _AB appended means address with base register
+ _D appended means 64 bit floating point constant
+ _S appended means 32 bit floating point constant. */
+
+enum
+{
+ M_LA,
+ M_LLA,
+ M_LA_TLS_GD,
+ M_LA_TLS_IE,
+ M_LB,
+ M_LBU,
+ M_LH,
+ M_LHU,
+ M_LW,
+ M_LWU,
+ M_LD,
+ M_SB,
+ M_SH,
+ M_SW,
+ M_SD,
+ M_FLW,
+ M_FLD,
+ M_FSW,
+ M_FSD,
+ M_CALL,
+ M_JUMP,
+ M_J,
+ M_LI,
+ M_VF,
+ M_NUM_MACROS
+};
+
+
+/* The order of overloaded instructions matters. Label arguments and
+ register arguments look the same. Instructions that can have either
+ for arguments must apear in the correct order in this table for the
+ assembler to pick the right one. In other words, entries with
+ immediate operands must apear after the same instruction with
+ registers.
+
+ Many instructions are short hand for other instructions (i.e., The
+ jal <register> instruction is short for jalr <register>). */
+
+extern const struct riscv_opcode riscv_builtin_opcodes[];
+extern const int bfd_riscv_num_builtin_opcodes;
+extern struct riscv_opcode *riscv_opcodes;
+extern int bfd_riscv_num_opcodes;
+#define NUMOPCODES bfd_riscv_num_opcodes
+
+#endif /* _MIPS_H_ */
diff --git a/binutils-2.21.1/ld/Makefile.am b/binutils-2.21.1/ld/Makefile.am
index 1280b64..5a7c71a 100644
--- a/binutils-2.21.1/ld/Makefile.am
+++ binutils-2.21.1/ld/Makefile.am
@@ -211,6 +211,7 @@ ALL_EMULATION_SOURCES = \
eelf32lppc.c \
eelf32lppcnto.c \
eelf32lppcsim.c \
+ eelf32lriscv.c \
eelf32lsmip.c \
eelf32ltsmip.c \
eelf32ltsmipn32.c \
@@ -454,6 +455,7 @@ ALL_64_EMULATION_SOURCES = \
eelf64btsmip.c \
eelf64hppa.c \
eelf64lppc.c \
+ eelf64lriscv.c \
eelf64ltsmip.c \
eelf64mmix.c \
eelf64ppc.c \
@@ -963,6 +965,10 @@ eelf32lppcsim.c: $(srcdir)/emulparams/elf32lppcsim.sh \
ldemul-list.h \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32lppcsim "$(tdir_elf32lppcsim)"
+eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \
+ $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \
+ $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32lriscv "$(tdir_elf32lriscv)"
eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \
$(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \
$(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \
@@ -1848,6 +1854,11 @@ eelf64lppc.c: $(srcdir)/emulparams/elf64lppc.sh \
ldemul-list.h \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf64lppc "$(tdir_elf64lppc)"
+eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \
+ $(srcdir)/emulparams/elf64lriscv-defs.sh \
+ $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \
+ $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf64lriscv "$(tdir_elf64lriscv)"
eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \
$(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \
$(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \
diff --git a/binutils-2.21.1/ld/Makefile.in b/binutils-2.21.1/ld/Makefile.in
index 00fcd72..2db7ce6 100644
--- a/binutils-2.21.1/ld/Makefile.in
+++ binutils-2.21.1/ld/Makefile.in
@@ -516,6 +516,7 @@ ALL_EMULATION_SOURCES = \
eelf32lppc.c \
eelf32lppcnto.c \
eelf32lppcsim.c \
+ eelf32lriscv.c \
eelf32lsmip.c \
eelf32ltsmip.c \
eelf32ltsmipn32.c \
@@ -758,6 +759,7 @@ ALL_64_EMULATION_SOURCES = \
eelf64btsmip.c \
eelf64hppa.c \
eelf64lppc.c \
+ eelf64lriscv.c \
eelf64ltsmip.c \
eelf64mmix.c \
eelf64ppc.c \
@@ -1098,6 +1100,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppcnto.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppcsim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lriscv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lsmip.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ltsmip.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32ltsmipn32.Po@am__quote@
@@ -1138,6 +1141,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lriscv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64ltsmip.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64mmix.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64ppc.Po@am__quote@
@@ -2398,6 +2402,10 @@ eelf32lppcsim.c: $(srcdir)/emulparams/elf32lppcsim.sh \
ldemul-list.h \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf32lppcsim "$(tdir_elf32lppcsim)"
+eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \
+ $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \
+ $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf32lriscv "$(tdir_elf32lriscv)"
eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \
$(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \
$(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \
@@ -3283,6 +3291,11 @@ eelf64lppc.c: $(srcdir)/emulparams/elf64lppc.sh \
ldemul-list.h \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf64lppc "$(tdir_elf64lppc)"
+eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \
+ $(srcdir)/emulparams/elf64lriscv-defs.sh \
+ $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \
+ $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} elf64lriscv "$(tdir_elf64lriscv)"
eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \
$(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \
$(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \
diff --git a/binutils-2.21.1/ld/configure.tgt b/binutils-2.21.1/ld/configure.tgt
index 90d7461..dc79744 100644
--- a/binutils-2.21.1/ld/configure.tgt
+++ binutils-2.21.1/ld/configure.tgt
@@ -504,6 +504,9 @@ powerpc-*-aix*) targ_emul=aixppc ;;
powerpc-*-beos*) targ_emul=aixppc ;;
powerpc-*-windiss*) targ_emul=elf32ppcwindiss ;;
powerpc-*-lynxos*) targ_emul=ppclynx ;;
+riscv*-*-*) targ_emul=elf64lriscv
+ targ_extra_emuls="elf32lriscv"
+ targ_extra_libpath=$targ_extra_emuls ;;
rs6000-*-aix[5-9]*) targ_emul=aix5rs6 ;;
rs6000-*-aix*) targ_emul=aixrs6
;;
diff --git a/binutils-2.21.1/ld/emulparams/elf32lriscv-defs.sh b/binutils-2.21.1/ld/emulparams/elf32lriscv-defs.sh
new file mode 100644
index 0000000..fba4f7f
--- /dev/null
+++ binutils-2.21.1/ld/emulparams/elf32lriscv-defs.sh
@@ -0,0 +1,59 @@
+# This is an ELF platform.
+SCRIPT_NAME=elf
+
+# Handle both big- and little-ended 32-bit MIPS objects.
+ARCH=riscv
+OUTPUT_FORMAT="elf32-littleriscv"
+
+TEMPLATE_NAME=elf32
+EXTRA_EM_FILE=riscvelf
+
+case "$EMULATION_NAME" in
+elf32*) ELFSIZE=32; LIBPATH_SUFFIX=32 ;;
+elf64*) ELFSIZE=64; LIBPATH_SUFFIX= ;;
+*) echo $0: unhandled emulation $EMULATION_NAME >&2; exit 1 ;;
+esac
+
+if test `echo "$host" | sed -e s/64//` = `echo "$target" | sed -e s/64//`; then
+ case " $EMULATION_LIBPATH " in
+ *" ${EMULATION_NAME} "*)
+ NATIVE=yes
+ ;;
+ esac
+fi
+
+GENERATE_SHLIB_SCRIPT=yes
+GENERATE_PIE_SCRIPT=yes
+
+TEXT_START_ADDR=0x10000000
+SHLIB_TEXT_START_ADDR=0x1000000
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+ENTRY=_start
+
+# Unlike most targets, the MIPS backend puts all dynamic relocations
+# in a single dynobj section, which it also calls ".rel.dyn". It does
+# this so that it can easily sort all dynamic relocations before the
+# output section has been populated.
+OTHER_GOT_RELOC_SECTIONS="
+ .rel.dyn ${RELOCATING-0} : { *(.rel.dyn) }
+"
+GOT=".got ${RELOCATING-0} : { *(.got) }"
+unset OTHER_READWRITE_SECTIONS
+unset OTHER_RELRO_SECTIONS
+
+# Magic symbols.
+TEXT_START_SYMBOLS='_ftext = . ;'
+DATA_START_SYMBOLS='_fdata = . ;'
+OTHER_BSS_SYMBOLS='_fbss = .;'
+
+INITIAL_READONLY_SECTIONS=".interp ${RELOCATING-0} : { *(.interp) }"
+SDATA_START_SYMBOLS="_gp = . + 0x800;
+ *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*)"
+if test -n "${CREATE_SHLIB}"; then
+ INITIAL_READONLY_SECTIONS=
+ SDATA_START_SYMBOLS=
+ OTHER_READONLY_SECTIONS=".srodata ${RELOCATING-0} : { *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) }"
+ unset GOT
+fi
+
+TEXT_DYNAMIC=
diff --git a/binutils-2.21.1/ld/emulparams/elf32lriscv.sh b/binutils-2.21.1/ld/emulparams/elf32lriscv.sh
new file mode 100644
index 0000000..8ccd147
--- /dev/null
+++ binutils-2.21.1/ld/emulparams/elf32lriscv.sh
@@ -0,0 +1,12 @@
+# If you change this file, please also look at files which source this one:
+# elf32ltsmipn32.sh
+
+. ${srcdir}/emulparams/elf32lriscv-defs.sh
+OUTPUT_FORMAT="elf32-littleriscv"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
+
+# Magic sections.
+OTHER_SECTIONS='
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+'
diff --git a/binutils-2.21.1/ld/emulparams/elf64lriscv-defs.sh b/binutils-2.21.1/ld/emulparams/elf64lriscv-defs.sh
new file mode 100644
index 0000000..abaf766
--- /dev/null
+++ binutils-2.21.1/ld/emulparams/elf64lriscv-defs.sh
@@ -0,0 +1,2 @@
+. ${srcdir}/emulparams/elf32lriscv-defs.sh
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
diff --git a/binutils-2.21.1/ld/emulparams/elf64lriscv.sh b/binutils-2.21.1/ld/emulparams/elf64lriscv.sh
new file mode 100644
index 0000000..a31964b
--- /dev/null
+++ binutils-2.21.1/ld/emulparams/elf64lriscv.sh
@@ -0,0 +1,11 @@
+# If you change this file, please also look at files which source this one:
+# elf64ltsmip.sh
+
+. ${srcdir}/emulparams/elf64lriscv-defs.sh
+OUTPUT_FORMAT="elf64-littleriscv"
+
+# Magic sections.
+OTHER_SECTIONS='
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+'
diff --git a/binutils-2.21.1/ld/emultempl/riscvelf.em b/binutils-2.21.1/ld/emultempl/riscvelf.em
new file mode 100644
index 0000000..89eda47
--- /dev/null
+++ binutils-2.21.1/ld/emultempl/riscvelf.em
@@ -0,0 +1,63 @@
+# This shell script emits a C file. -*- C -*-
+# Copyright 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+fragment <<EOF
+
+#include "ldmain.h"
+#include "ldctor.h"
+#include "elf/riscv.h"
+#include "elfxx-riscv.h"
+
+#define is_riscv_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == MIPS_ELF_DATA)
+
+static void
+riscv_after_parse (void)
+{
+ /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different
+ ways. .gnu.hash needs symbols to be grouped by hash code whereas the
+ MIPS ABI requires a mapping between the GOT and the symbol table. */
+ if (link_info.emit_gnu_hash)
+ {
+ einfo ("%X%P: .gnu.hash is incompatible with the MIPS ABI\n");
+ link_info.emit_hash = TRUE;
+ link_info.emit_gnu_hash = FALSE;
+ }
+ after_parse_default ();
+}
+
+static void
+riscv_before_allocation (void)
+{
+ gld${EMULATION_NAME}_before_allocation ();
+
+ if (link_info.discard == discard_sec_merge)
+ link_info.discard = discard_l;
+
+ if (RELAXATION_DISABLED_BY_DEFAULT)
+ ENABLE_RELAXATION;
+}
+
+EOF
+
+LDEMUL_AFTER_PARSE=riscv_after_parse
+LDEMUL_BEFORE_ALLOCATION=riscv_before_allocation
diff --git a/binutils-2.21.1/ld/ld.texinfo b/binutils-2.21.1/ld/ld.texinfo
index 879bcfc..15e82b7 100644
--- a/binutils-2.21.1/ld/ld.texinfo
+++ binutils-2.21.1/ld/ld.texinfo
@@ -138,15 +138,15 @@ in the section entitled ``GNU Free Documentation License''.
@ifset I960
* i960:: ld and the Intel 960 family
@end ifset
+@ifset M68HC11
+* M68HC11/68HC12:: ld and the Motorola 68HC11 and 68HC12 families
+@end ifset
@ifset ARM
* ARM:: ld and the ARM family
@end ifset
@ifset HPPA
* HPPA ELF32:: ld and HPPA 32-bit ELF
@end ifset
-@ifset M68HC11
-* M68HC11/68HC12:: ld and the Motorola 68HC11 and 68HC12 families
-@end ifset
@ifset M68K
* M68K:: ld and Motorola 68K family
@end ifset
@@ -5889,6 +5889,9 @@ functionality are not listed.
@ifset I960
* i960:: @command{ld} and the Intel 960 family
@end ifset
+@ifset M68HC11
+* M68HC11/68HC12:: @code{ld} and the Motorola 68HC11 and 68HC12 families
+@end ifset
@ifset ARM
* ARM:: @command{ld} and the ARM family
@end ifset
@@ -5904,9 +5907,6 @@ functionality are not listed.
@ifset MSP430
* MSP430:: @command{ld} and MSP430
@end ifset
-@ifset M68HC11
-* M68HC11/68HC12:: @code{ld} and the Motorola 68HC11 and 68HC12 families
-@end ifset
@ifset POWERPC
* PowerPC ELF32:: @command{ld} and PowerPC 32-bit ELF Support
@end ifset
@@ -7694,7 +7694,7 @@ If you have more than one @code{SECT} statement for the same
@printindex cp
@tex
-% I think something like @colophon should be in texinfo. In the
+% I think something like @@colophon should be in texinfo. In the
% meantime:
\long\def\colophon{\hbox to0pt{}\vfill
\centerline{The body of this manual is set in}
@@ -7705,7 +7705,7 @@ If you have more than one @code{SECT} statement for the same
\centerline{{\sl\fontname\tensl\/}}
\centerline{are used for emphasis.}\vfill}
\page\colophon
-% Blame: doc@cygnus.com, 28mar91.
+% Blame: doc@@cygnus.com, 28mar91.
@end tex
@bye
diff --git a/binutils-2.21.1/opcodes/configure b/binutils-2.21.1/opcodes/configure
index fe7c01e..b4e9869 100755
--- a/binutils-2.21.1/opcodes/configure
+++ binutils-2.21.1/opcodes/configure
@@ -12462,6 +12462,7 @@ if test x${all_targets} = xfalse ; then
bfd_powerpc_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_powerpc_64_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_pyramid_arch) ;;
+ bfd_riscv_arch) ta="$ta riscv-dis.lo riscv-opc.lo" ;;
bfd_romp_arch) ;;
bfd_rs6000_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_rx_arch) ta="$ta rx-dis.lo rx-decode.lo";;
diff --git a/binutils-2.21.1/opcodes/configure.in b/binutils-2.21.1/opcodes/configure.in
index 0518781..8bdf4fa 100644
--- a/binutils-2.21.1/opcodes/configure.in
+++ binutils-2.21.1/opcodes/configure.in
@@ -268,6 +268,7 @@ if test x${all_targets} = xfalse ; then
bfd_powerpc_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_powerpc_64_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_pyramid_arch) ;;
+ bfd_riscv_arch) ta="$ta riscv-dis.lo riscv-opc.lo" ;;
bfd_romp_arch) ;;
bfd_rs6000_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_rx_arch) ta="$ta rx-dis.lo rx-decode.lo";;
diff --git a/binutils-2.21.1/opcodes/disassemble.c b/binutils-2.21.1/opcodes/disassemble.c
index 0fb35ac..cef365e 100644
--- a/binutils-2.21.1/opcodes/disassemble.c
+++ binutils-2.21.1/opcodes/disassemble.c
@@ -338,6 +338,14 @@ disassembler (abfd)
disassemble = print_insn_little_powerpc;
break;
#endif
+#ifdef ARCH_riscv
+ case bfd_arch_riscv:
+ if (bfd_big_endian (abfd))
+ disassemble = print_insn_big_riscv;
+ else
+ disassemble = print_insn_little_riscv;
+ break;
+#endif
#ifdef ARCH_rs6000
case bfd_arch_rs6000:
if (bfd_get_mach (abfd) == bfd_mach_ppc_620)
diff --git a/binutils-2.21.1/opcodes/riscv-dis.c b/binutils-2.21.1/opcodes/riscv-dis.c
new file mode 100644
index 0000000..6f701d5
--- /dev/null
+++ binutils-2.21.1/opcodes/riscv-dis.c
@@ -0,0 +1,783 @@
+/* Print mips instructions for GDB, the GNU debugger, or for objdump.
+ Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2005, 2007, 2008
+ Free Software Foundation, Inc.
+ Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
+
+ This file is part of the GNU opcodes library.
+
+ This library 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, or (at your option)
+ any later version.
+
+ It 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 "dis-asm.h"
+#include "libiberty.h"
+#include "opcode/riscv.h"
+#include "opintl.h"
+#include "elf-bfd.h"
+#include "elf/riscv.h"
+
+#include <stdint.h>
+#include <assert.h>
+
+/* FIXME: These should be shared with gdb somehow. */
+
+static const char * const mips_gpr_names_numeric[32] =
+{
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31"
+};
+
+static const char* mips_gpr_names_abi[32] = {
+ "zero", "ra", "s0", "s1", "s2", "s3", "s4", "s5",
+ "s6", "s7", "s8", "s9", "s10", "s11", "sp", "tp",
+ "v0", "v1", "a0", "a1", "a2", "a3", "a4", "a5",
+ "a6", "a7", "t0", "t1", "t2", "t3", "t4", "gp"
+};
+
+
+static const char * const mips_fpr_names_numeric[32] =
+{
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
+};
+
+static const char* mips_fpr_names_abi[32] = {
+ "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+ "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
+ "fv0", "fv1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
+ "fa6", "fa7", "ft0", "ft1", "ft2", "ft3", "ft4", "ft5"
+};
+
+static const char * const mips_vgr_reg_names_riscv[32] =
+{
+ "vx0", "vx1", "vx2", "vx3", "vx4", "vx5", "vx6", "vx7",
+ "vx8", "vx9", "vx10", "vx11", "vx12", "vx13", "vx14", "vx15",
+ "vx16", "vx17", "vx18", "vx19", "vx20", "vx21", "vx22", "vx23",
+ "vx24", "vx25", "vx26", "vx27", "vx28", "vx29", "vx30", "vx31"
+};
+
+static const char * const mips_vfp_reg_names_riscv[32] =
+{
+ "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7",
+ "vf8", "vf9", "vf10", "vf11", "vf12", "vf13", "vf14", "vf15",
+ "vf16", "vf17", "vf18", "vf19", "vf20", "vf21", "vf22", "vf23",
+ "vf24", "vf25", "vf26", "vf27", "vf28", "vf29", "vf30", "vf31"
+};
+
+struct mips_abi_choice
+{
+ const char * name;
+ const char * const *gpr_names;
+ const char * const *fpr_names;
+};
+
+struct mips_abi_choice mips_abi_choices[] =
+{
+ { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
+ { "32", mips_gpr_names_abi, mips_fpr_names_abi },
+ { "64", mips_gpr_names_abi, mips_fpr_names_abi },
+};
+
+struct mips_arch_choice
+{
+ const char *name;
+ int bfd_mach_valid;
+ unsigned long bfd_mach;
+};
+
+const struct mips_arch_choice mips_arch_choices[] =
+{
+ { "numeric", 0, 0 },
+ { "rv32", 1, bfd_mach_riscv32 },
+ { "rv64", 1, bfd_mach_riscv64 },
+};
+
+struct riscv_private_data
+{
+ bfd_vma gp;
+ bfd_vma print_addr;
+ bfd_vma hi_addr[OP_MASK_RD + 1];
+};
+
+/* ISA and processor type to disassemble for, and register names to use.
+ set_default_mips_dis_options and parse_mips_dis_options fill in these
+ values. */
+static const char * const *mips_gpr_names;
+static const char * const *mips_fpr_names;
+
+/* Other options */
+static int no_aliases; /* If set disassemble as most general inst. */
+
+static const struct mips_abi_choice *
+choose_abi_by_name (const char *name, unsigned int namelen)
+{
+ const struct mips_abi_choice *c;
+ unsigned int i;
+
+ for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
+ if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
+ && strlen (mips_abi_choices[i].name) == namelen)
+ c = &mips_abi_choices[i];
+
+ return c;
+}
+
+static void
+set_default_mips_dis_options (struct disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ mips_gpr_names = mips_gpr_names_abi;
+ mips_fpr_names = mips_fpr_names_abi;
+ no_aliases = 0;
+}
+
+static void
+parse_mips_dis_option (const char *option, unsigned int len)
+{
+ unsigned int i, optionlen, vallen;
+ const char *val;
+ const struct mips_abi_choice *chosen_abi;
+
+ /* Try to match options that are simple flags */
+ if (CONST_STRNEQ (option, "no-aliases"))
+ {
+ no_aliases = 1;
+ return;
+ }
+
+ /* Look for the = that delimits the end of the option name. */
+ for (i = 0; i < len; i++)
+ if (option[i] == '=')
+ break;
+
+ if (i == 0) /* Invalid option: no name before '='. */
+ return;
+ if (i == len) /* Invalid option: no '='. */
+ return;
+ if (i == (len - 1)) /* Invalid option: no value after '='. */
+ return;
+
+ optionlen = i;
+ val = option + (optionlen + 1);
+ vallen = len - (optionlen + 1);
+
+ if (strncmp ("gpr-names", option, optionlen) == 0
+ && strlen ("gpr-names") == optionlen)
+ {
+ chosen_abi = choose_abi_by_name (val, vallen);
+ if (chosen_abi != NULL)
+ mips_gpr_names = chosen_abi->gpr_names;
+ return;
+ }
+
+ if (strncmp ("fpr-names", option, optionlen) == 0
+ && strlen ("fpr-names") == optionlen)
+ {
+ chosen_abi = choose_abi_by_name (val, vallen);
+ if (chosen_abi != NULL)
+ mips_fpr_names = chosen_abi->fpr_names;
+ return;
+ }
+
+ /* Invalid option. */
+}
+
+static void
+parse_mips_dis_options (const char *options)
+{
+ const char *option_end;
+
+ if (options == NULL)
+ return;
+
+ while (*options != '\0')
+ {
+ /* Skip empty options. */
+ if (*options == ',')
+ {
+ options++;
+ continue;
+ }
+
+ /* We know that *options is neither NUL or a comma. */
+ option_end = options + 1;
+ while (*option_end != ',' && *option_end != '\0')
+ option_end++;
+
+ parse_mips_dis_option (options, option_end - options);
+
+ /* Go on to the next one. If option_end points to a comma, it
+ will be skipped above. */
+ options = option_end;
+ }
+}
+
+/* Print one argument from an array. */
+
+static void
+arg_print (struct disassemble_info *info, unsigned long val,
+ const char* const* array, size_t size)
+{
+ const char *s = val >= size || array[val] == NULL ? "unknown" : array[val];
+ (*info->fprintf_func) (info->stream, "%s", s);
+}
+
+static void
+maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset)
+{
+ if (pd->hi_addr[base_reg] != (bfd_vma)-1)
+ {
+ pd->print_addr = pd->hi_addr[base_reg] + offset;
+ pd->hi_addr[base_reg] = -1;
+ }
+ else if (base_reg == GP_REG && pd->gp != (bfd_vma)-1)
+ pd->print_addr = pd->gp + offset;
+ else if (base_reg == TP_REG)
+ pd->print_addr = offset;
+}
+
+/* Print insn arguments for 32/64-bit code. */
+
+static void
+print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
+{
+ struct riscv_private_data *pd = info->private_data;
+ int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
+ int rd = (l >> OP_SH_RD) & OP_MASK_RD;
+
+ if (*d != '\0')
+ (*info->fprintf_func) (info->stream, "\t");
+
+ for (; *d != '\0'; d++)
+ {
+ switch (*d)
+ {
+ /* Xcustom */
+ case '^':
+ switch (*++d)
+ {
+ case 'd':
+ (*info->fprintf_func) (info->stream, "%d", rd);
+ break;
+ case 's':
+ (*info->fprintf_func) (info->stream, "%d", rs1);
+ break;
+ case 't':
+ (*info->fprintf_func)
+ ( info->stream, "%d", ((l >> OP_SH_RS2) & OP_MASK_RS2));
+ break;
+ case 'j':
+ (*info->fprintf_func)
+ ( info->stream, "%d", ((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM));
+ break;
+ }
+ break;
+
+ /* Xhwacha */
+ case '#':
+ switch ( *++d ) {
+ case 'g':
+ (*info->fprintf_func)
+ ( info->stream, "%d",
+ ((l >> OP_SH_IMMNGPR) & OP_MASK_IMMNGPR));
+ break;
+ case 'f':
+ (*info->fprintf_func)
+ ( info->stream, "%d",
+ ((l >> OP_SH_IMMNFPR) & OP_MASK_IMMNFPR));
+ break;
+ case 'p':
+ (*info->fprintf_func)
+ ( info->stream, "%d",
+ ((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM));
+ break;
+ case 'n':
+ (*info->fprintf_func)
+ ( info->stream, "%d",
+ (((l >> OP_SH_IMMSEGNELM) & OP_MASK_IMMSEGNELM) + 1));
+ break;
+ case 'd':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vgr_reg_names_riscv[(l >> OP_SH_VRD) & OP_MASK_VRD]);
+ break;
+ case 's':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vgr_reg_names_riscv[(l >> OP_SH_VRS) & OP_MASK_VRS]);
+ break;
+ case 't':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vgr_reg_names_riscv[(l >> OP_SH_VRT) & OP_MASK_VRT]);
+ break;
+ case 'r':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vgr_reg_names_riscv[(l >> OP_SH_VRR) & OP_MASK_VRR]);
+ break;
+ case 'D':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vfp_reg_names_riscv[(l >> OP_SH_VFD) & OP_MASK_VFD]);
+ break;
+ case 'S':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vfp_reg_names_riscv[(l >> OP_SH_VFS) & OP_MASK_VFS]);
+ break;
+ case 'T':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vfp_reg_names_riscv[(l >> OP_SH_VFT) & OP_MASK_VFT]);
+ break;
+ case 'R':
+ (*info->fprintf_func)
+ ( info->stream, "%s",
+ mips_vfp_reg_names_riscv[(l >> OP_SH_VFR) & OP_MASK_VFR]);
+ break;
+ }
+ break;
+
+ case ',':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ (*info->fprintf_func) (info->stream, "%c", *d);
+ break;
+
+ case '0':
+ break;
+
+ case 'b':
+ case 's':
+ (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[rs1]);
+ break;
+
+ case 't':
+ (*info->fprintf_func) (info->stream, "%s",
+ mips_gpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]);
+ break;
+
+ case 'u':
+ (*info->fprintf_func) (info->stream, "0x%lx", (uint32_t)EXTRACT_UTYPE_IMM (l) << RISCV_IMM_BITS >> RISCV_IMM_BITS);
+ break;
+
+ case 'm':
+ arg_print(info, (l >> OP_SH_RM) & OP_MASK_RM,
+ riscv_rm, ARRAY_SIZE(riscv_rm));
+ break;
+
+ case 'P':
+ arg_print(info, (l >> OP_SH_PRED) & OP_MASK_PRED,
+ riscv_pred_succ, ARRAY_SIZE(riscv_pred_succ));
+ break;
+
+ case 'Q':
+ arg_print(info, (l >> OP_SH_SUCC) & OP_MASK_SUCC,
+ riscv_pred_succ, ARRAY_SIZE(riscv_pred_succ));
+ break;
+
+ case 'o':
+ maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
+ case 'j':
+ if ((l & MASK_ADDI) == MATCH_ADDI)
+ maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l));
+ (*info->fprintf_func) (info->stream, "%d", EXTRACT_ITYPE_IMM (l));
+ break;
+
+ case 'q':
+ maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l));
+ (*info->fprintf_func) (info->stream, "%d", EXTRACT_STYPE_IMM (l));
+ break;
+
+ case 'a':
+ info->target = EXTRACT_UJTYPE_IMM (l) + pc;
+ (*info->print_address_func) (info->target, info);
+ break;
+
+ case 'p':
+ info->target = EXTRACT_SBTYPE_IMM (l) + pc;
+ (*info->print_address_func) (info->target, info);
+ break;
+
+ case 'd':
+ if ((l & MASK_AUIPC) == MATCH_AUIPC)
+ pd->hi_addr[rd] = pc + (EXTRACT_UTYPE_IMM (l) << RISCV_IMM_BITS);
+ else if ((l & MASK_LUI) == MATCH_LUI)
+ pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l) << RISCV_IMM_BITS;
+ (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[rd]);
+ break;
+
+ case 'z':
+ (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
+ break;
+
+ case '>':
+ (*info->fprintf_func) (info->stream, "0x%lx",
+ (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
+ break;
+
+ case '<':
+ (*info->fprintf_func) (info->stream, "0x%lx",
+ (l >> OP_SH_SHAMTW) & OP_MASK_SHAMTW);
+ break;
+
+ case 'S':
+ case 'U':
+ (*info->fprintf_func) (info->stream, "%s", mips_fpr_names[rs1]);
+ break;
+
+ case 'T':
+ (*info->fprintf_func) (info->stream, "%s",
+ mips_fpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]);
+ break;
+
+ case 'D':
+ (*info->fprintf_func) (info->stream, "%s", mips_fpr_names[rd]);
+ break;
+
+ case 'R':
+ (*info->fprintf_func) (info->stream, "%s",
+ mips_fpr_names[(l >> OP_SH_RS3) & OP_MASK_RS3]);
+ break;
+
+ case 'E':
+ {
+ const char* csr_name = "unknown";
+ switch ((l >> OP_SH_CSR) & OP_MASK_CSR)
+ {
+ #define DECLARE_CSR(name, num) case num: csr_name = #name; break;
+ #include "opcode/riscv-opc.h"
+ #undef DECLARE_CSR
+ }
+ (*info->fprintf_func) (info->stream, "%s", csr_name);
+ break;
+ }
+
+ case 'Z':
+ (*info->fprintf_func) (info->stream, "%d", rs1);
+ break;
+
+ default:
+ /* xgettext:c-format */
+ (*info->fprintf_func) (info->stream,
+ _("# internal error, undefined modifier (%c)"),
+ *d);
+ return;
+ }
+ }
+}
+
+#if 0
+static unsigned long
+riscv_rvc_uncompress(unsigned long rvc_insn)
+{
+ #define IS_INSN(x, op) (((x) & MASK_##op) == MATCH_##op)
+ #define EXTRACT_OPERAND(x, op) (((x) >> OP_SH_##op) & OP_MASK_##op)
+
+ int crd = EXTRACT_OPERAND(rvc_insn, CRD);
+ int crs1 = EXTRACT_OPERAND(rvc_insn, CRS1);
+ int crs2 = EXTRACT_OPERAND(rvc_insn, CRS2);
+ int crds = EXTRACT_OPERAND(rvc_insn, CRDS);
+ int crs1s = EXTRACT_OPERAND(rvc_insn, CRS1S);
+ int crs2s = EXTRACT_OPERAND(rvc_insn, CRS2S);
+ int crs2bs = EXTRACT_OPERAND(rvc_insn, CRS2BS);
+
+ int cimm6 = EXTRACT_OPERAND(rvc_insn, CIMM6);
+ int imm6 = ((int32_t)cimm6 << 26 >> 26) & (RISCV_IMM_REACH-1);
+ int imm6x4 = (((int32_t)cimm6 << 26 >> 26)*4) & (RISCV_IMM_REACH-1);
+ int imm6x4lo = imm6x4 & ((1<<RISCV_IMMLO_BITS)-1);
+ int imm6x4hi = (imm6x4 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1);
+ int imm6x8 = (((int32_t)cimm6 << 26 >> 26)*8) & (RISCV_IMM_REACH-1);
+ int imm6x8lo = imm6x8 & ((1<<RISCV_IMMLO_BITS)-1);
+ int imm6x8hi = (imm6x8 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1);
+
+ int cimm5 = EXTRACT_OPERAND(rvc_insn, CIMM5);
+ int imm5 = ((int32_t)cimm5 << 27 >> 27) & (RISCV_IMM_REACH-1);
+ int imm5lo = imm5 & ((1<<RISCV_IMMLO_BITS)-1);
+ int imm5hi = (imm5 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1);
+ int imm5x4 = (((int32_t)cimm5 << 27 >> 27)*4) & (RISCV_IMM_REACH-1);
+ int imm5x4lo = imm5x4 & ((1<<RISCV_IMMLO_BITS)-1);
+ int imm5x4hi = (imm5x4 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1);
+ int imm5x8 = (((int32_t)cimm5 << 27 >> 27)*8) & (RISCV_IMM_REACH-1);
+ int imm5x8lo = imm5x8 & ((1<<RISCV_IMMLO_BITS)-1);
+ int imm5x8hi = (imm5x8 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1);
+
+ int cimm10 = EXTRACT_OPERAND(rvc_insn, CIMM10);
+ int jt10 = ((int32_t)cimm10 << 22 >> 22) & ((1<<RISCV_JUMP_BITS)-1);
+
+ if(IS_INSN(rvc_insn, C_ADDI))
+ {
+ if(crd == 0)
+ {
+ if(imm6 & 0x20)
+ return MATCH_JALR | (LINK_REG << OP_SH_RD) | (crs1 << OP_SH_RS1);
+ else
+ return MATCH_JALR | (crs1 << OP_SH_RS1);
+ }
+ return MATCH_ADDI | (crd << OP_SH_RD) | (crd << OP_SH_RS1) |
+ (imm6 << OP_SH_IMMEDIATE);
+ }
+ if(IS_INSN(rvc_insn, C_ADDIW))
+ return MATCH_ADDIW | (crd << OP_SH_RD) | (crd << OP_SH_RS1) | (imm6 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_LI))
+ return MATCH_ADDI | (crd << OP_SH_RD) | (imm6 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_MOVE))
+ return MATCH_ADDI | (crd << OP_SH_RD) | (crs1 << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SLLI))
+ return MATCH_SLLI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SLLI32))
+ return MATCH_SLLI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SRLI))
+ return MATCH_SRLI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SRLI32))
+ return MATCH_SRLI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SRAI))
+ return MATCH_SRAI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SRAI32))
+ return MATCH_SRAI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_SLLIW))
+ return MATCH_SLLIW | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS1);
+ if(IS_INSN(rvc_insn, C_ADD))
+ return MATCH_ADD | (crd << OP_SH_RD) | (crs1 << OP_SH_RS1) | (crd << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_SUB))
+ return MATCH_SUB | (crd << OP_SH_RD) | (crs1 << OP_SH_RS1) | (crd << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_ADD3))
+ return MATCH_ADD | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_SUB3))
+ return MATCH_SUB | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_AND3))
+ return MATCH_AND | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_OR3))
+ return MATCH_OR | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RS2);
+ if(IS_INSN(rvc_insn, C_J))
+ return MATCH_JAL | (jt10 << OP_SH_TARGET);
+ if(IS_INSN(rvc_insn, C_BEQ))
+ return MATCH_BEQ | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5lo << OP_SH_IMMLO) | (imm5hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_BNE))
+ return MATCH_BNE | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5lo << OP_SH_IMMLO) | (imm5hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_LDSP))
+ return MATCH_LD | (30 << OP_SH_RS1) | (crd << OP_SH_RD) | (imm6x8 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_LWSP))
+ return MATCH_LW | (30 << OP_SH_RS1) | (crd << OP_SH_RD) | (imm6x4 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_SDSP))
+ return MATCH_SD | (30 << OP_SH_RS1) | (crs2 << OP_SH_RS2) | (imm6x8lo << OP_SH_IMMLO) | (imm6x8hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_SWSP))
+ return MATCH_SW | (30 << OP_SH_RS1) | (crs2 << OP_SH_RS2) | (imm6x4lo << OP_SH_IMMLO) | (imm6x4hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_LD))
+ return MATCH_LD | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x8 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_LW))
+ return MATCH_LW | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x4 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_SD))
+ return MATCH_SD | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5x8lo << OP_SH_IMMLO) | (imm5x8hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_SW))
+ return MATCH_SW | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5x4lo << OP_SH_IMMLO) | (imm5x4hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_LD0))
+ return MATCH_LD | (crs1 << OP_SH_RS1) | (crd << OP_SH_RD);
+ if(IS_INSN(rvc_insn, C_LW0))
+ return MATCH_LW | (crs1 << OP_SH_RS1) | (crd << OP_SH_RD);
+ if(IS_INSN(rvc_insn, C_FLD))
+ return MATCH_FLD | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x8 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_FLW))
+ return MATCH_FLW | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x4 << OP_SH_IMMEDIATE);
+ if(IS_INSN(rvc_insn, C_FSD))
+ return MATCH_FSD | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5x8lo << OP_SH_IMMLO) | (imm5x8hi << OP_SH_IMMHI);
+ if(IS_INSN(rvc_insn, C_FSW))
+ return MATCH_FSW | (rvc_rs1_regmap[crs1s] << OP_SH_RS1) | (rvc_rs2_regmap[crs2s] << OP_SH_RS2) | (imm5x4lo << OP_SH_IMMLO) | (imm5x4hi << OP_SH_IMMHI);
+
+ return rvc_insn;
+}
+#endif
+
+/* Print the mips instruction at address MEMADDR in debugged memory,
+ on using INFO. Returns length of the instruction, in bytes.
+ BIGENDIAN must be 1 if this is big-endian code, 0 if
+ this is little-endian code. */
+
+static int
+print_insn_mips (bfd_vma memaddr, insn_t word, disassemble_info *info)
+{
+ const struct riscv_opcode *op;
+ static bfd_boolean init = 0;
+ static const char *extension = NULL;
+ static const struct riscv_opcode *mips_hash[OP_MASK_OP + 1];
+ struct riscv_private_data *pd;
+ int insnlen;
+
+ /* Build a hash table to shorten the search time. */
+ if (! init)
+ {
+ unsigned int i;
+ unsigned int e_flags = elf_elfheader (info->section->owner)->e_flags;
+ extension = riscv_elf_flag_to_name(EF_GET_RISCV_EXT(e_flags));
+
+ for (i = 0; i <= OP_MASK_OP; i++)
+ for (op = riscv_opcodes; op < &riscv_opcodes[NUMOPCODES]; op++)
+ if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
+ {
+ mips_hash[i] = op;
+ break;
+ }
+
+ init = 1;
+ }
+
+ if (info->private_data == NULL)
+ {
+ int i;
+
+ pd = info->private_data = calloc(1, sizeof (struct riscv_private_data));
+ pd->gp = -1;
+ pd->print_addr = -1;
+ for (i = 0; i < (int) ARRAY_SIZE(pd->hi_addr); i++)
+ pd->hi_addr[i] = -1;
+
+ for (i = 0; i < info->symtab_size; i++)
+ if (strcmp (bfd_asymbol_name (info->symtab[i]), "_gp") == 0)
+ pd->gp = bfd_asymbol_value (info->symtab[i]);
+ }
+ else
+ pd = info->private_data;
+
+ insnlen = riscv_insn_length (word);
+
+#if 0
+ if (insnlen == 2)
+ word = riscv_rvc_uncompress(word);
+#endif
+
+ info->bytes_per_chunk = insnlen % 4 == 0 ? 4 : 2;
+ info->bytes_per_line = 8;
+ info->display_endian = info->endian;
+ info->insn_info_valid = 1;
+ info->branch_delay_insns = 0;
+ info->data_size = 0;
+ info->insn_type = dis_nonbranch;
+ info->target = 0;
+ info->target2 = 0;
+
+ op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
+ if (op != NULL)
+ {
+ for (; op < &riscv_opcodes[NUMOPCODES]; op++)
+ {
+ if ((op->match_func) (op, word)
+ && !(no_aliases && (op->pinfo & INSN_ALIAS))
+ && !(op->subset[0] == 'X' && strcmp(op->subset, extension)))
+ {
+ (*info->fprintf_func) (info->stream, "%s", op->name);
+ print_insn_args (op->args, word, memaddr, info);
+ if (pd->print_addr != (bfd_vma)-1)
+ {
+ info->target = pd->print_addr;
+ (*info->fprintf_func) (info->stream, " # ", word);
+ (*info->print_address_func) (info->target, info);
+ pd->print_addr = -1;
+ }
+ return insnlen;
+ }
+ }
+ }
+
+ /* Handle undefined instructions. */
+ info->insn_type = dis_noninsn;
+ (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long)word);
+ return insnlen;
+}
+
+/* In an environment where we do not know the symbol type of the
+ instruction we are forced to assume that the low order bit of the
+ instructions' address may mark it as a mips16 instruction. If we
+ are single stepping, or the pc is within the disassembled function,
+ this works. Otherwise, we need a clue. Sometimes. */
+
+static int
+_print_insn_mips (bfd_vma memaddr,
+ struct disassemble_info *info,
+ enum bfd_endian endianness)
+{
+ uint16_t i2;
+ insn_t insn = 0;
+ bfd_vma n;
+ int status;
+
+ set_default_mips_dis_options (info);
+ parse_mips_dis_options (info->disassembler_options);
+
+ /* Instructions are stored as a sequence of 2-byte packets in little-endian
+ order. (Within a packet, the byte order is the target endianness). */
+ for (n = 0; n < sizeof(insn) && n < riscv_insn_length (insn); n += 2)
+ {
+ status = (*info->read_memory_func) (memaddr + n, (bfd_byte*)&i2, 2, info);
+ if (status != 0)
+ {
+ if (n > 0) /* Don't fail just because we fell off the end. */
+ break;
+ (*info->memory_error_func) (status, memaddr, info);
+ return status;
+ }
+
+ i2 = endianness == BFD_ENDIAN_BIG ? bfd_getb16 (&i2) : bfd_getl16 (&i2);
+ insn |= (insn_t)i2 << (8*n);
+ }
+
+ return print_insn_mips (memaddr, insn, info);
+}
+
+int
+print_insn_big_riscv (bfd_vma memaddr ATTRIBUTE_UNUSED,
+ struct disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
+}
+
+int
+print_insn_little_riscv (bfd_vma memaddr, struct disassemble_info *info)
+{
+ return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
+}
+
+void
+print_mips_disassembler_options (FILE *stream)
+{
+ unsigned int i;
+
+ fprintf (stream, _("\n\
+The following MIPS specific disassembler options are supported for use\n\
+with the -M switch (multiple options should be separated by commas):\n"));
+
+ fprintf (stream, _("\n\
+ gpr-names=ABI Print GPR names according to specified ABI.\n\
+ Default: based on binary being disassembled.\n"));
+
+ fprintf (stream, _("\n\
+ fpr-names=ABI Print FPR names according to specified ABI.\n\
+ Default: numeric.\n"));
+
+ fprintf (stream, _("\n\
+ For the options above, the following values are supported for \"ABI\":\n\
+ "));
+ for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
+ fprintf (stream, " %s", mips_abi_choices[i].name);
+ fprintf (stream, _("\n"));
+
+ fprintf (stream, _("\n"));
+}
diff --git a/binutils-2.21.1/opcodes/riscv-opc.c b/binutils-2.21.1/opcodes/riscv-opc.c
new file mode 100644
index 0000000..c110732
--- /dev/null
+++ binutils-2.21.1/opcodes/riscv-opc.c
@@ -0,0 +1,686 @@
+/* mips-opc.c -- MIPS opcode list.
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Contributed by Ralph Campbell and OSF
+ Commented and modified by Ian Lance Taylor, Cygnus Support
+ Extended for MIPS32 support by Anders Norlander, and by SiByte, Inc.
+ MIPS-3D, MDMX, and MIPS32 Release 2 support added by Broadcom
+ Corporation (SiByte).
+
+ This file is part of the GNU opcodes library.
+
+ This library 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, or (at your option)
+ any later version.
+
+ It 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 file; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include <stdio.h>
+#include "sysdep.h"
+#include "opcode/riscv.h"
+
+/* Short hand so the lines aren't too long. */
+
+/* The order of overloaded instructions matters. Label arguments and
+ register arguments look the same. Instructions that can have either
+ for arguments must apear in the correct order in this table for the
+ assembler to pick the right one. In other words, entries with
+ immediate operands must apear after the same instruction with
+ registers.
+
+ Because of the lookup algorithm used, entries with the same opcode
+ name must be contiguous. */
+
+#define WR_xd INSN_WRITE_GPR_D
+#define WR_fd INSN_WRITE_FPR_D
+#define RD_xs1 INSN_READ_GPR_S
+#define RD_xs2 INSN_READ_GPR_T
+#define RD_fs1 INSN_READ_FPR_S
+#define RD_fs2 INSN_READ_FPR_T
+#define RD_fs3 INSN_READ_FPR_R
+
+#define MASK_RS1 (OP_MASK_RS1 << OP_SH_RS1)
+#define MASK_RS2 (OP_MASK_RS2 << OP_SH_RS2)
+#define MASK_RD (OP_MASK_RD << OP_SH_RD)
+#define MASK_IMM ENCODE_ITYPE_IMM(-1U)
+#define MASK_UIMM ENCODE_UTYPE_IMM(-1U)
+#define MASK_RM (OP_MASK_RM << OP_SH_RM)
+#define MASK_PRED (OP_MASK_PRED << OP_SH_PRED)
+#define MASK_SUCC (OP_MASK_SUCC << OP_SH_SUCC)
+#define MASK_AQ (OP_MASK_AQ << OP_SH_AQ)
+#define MASK_RL (OP_MASK_RL << OP_SH_RL)
+#define MASK_AQRL (MASK_AQ | MASK_RL)
+
+static int match_opcode(const struct riscv_opcode *op, insn_t insn)
+{
+ return (insn & op->mask) == op->match;
+}
+
+static int match_never(const struct riscv_opcode *op ATTRIBUTE_UNUSED,
+ insn_t insn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int match_rs1_eq_rs2(const struct riscv_opcode *op, insn_t insn)
+{
+ return match_opcode(op, insn) &&
+ ((insn & MASK_RS1) >> OP_SH_RS1) == ((insn & MASK_RS2) >> OP_SH_RS2);
+}
+
+const struct riscv_opcode riscv_builtin_opcodes[] =
+{
+/* These instructions appear first so that the disassembler will find
+ them first. The assemblers uses a hash table based on the
+ instruction name anyhow. */
+/* name, isa, operands, match, mask, pinfo */
+{"unimp", "I", "", 0, 0xffff, match_opcode, 0 },
+{"nop", "I", "", MATCH_ADDI, MASK_ADDI | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS },
+{"li", "I", "d,j", MATCH_ADDI, MASK_ADDI | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd }, /* addi */
+{"li", "I", "d,I", 0, (int) M_LI, match_never, INSN_MACRO },
+{"mv", "I", "d,s", MATCH_ADDI, MASK_ADDI | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"move", "I", "d,s", MATCH_ADDI, MASK_ADDI | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"b", "I", "p", MATCH_BEQ, MASK_BEQ | MASK_RS1 | MASK_RS2, match_opcode, 0 },/* beq 0,0 */
+{"andi", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, WR_xd|RD_xs1 },
+{"and", "I", "d,s,t", MATCH_AND, MASK_AND, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"and", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"beqz", "I", "s,p", MATCH_BEQ, MASK_BEQ | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
+{"beq", "I", "s,t,p", MATCH_BEQ, MASK_BEQ, match_opcode, RD_xs1|RD_xs2 },
+{"blez", "I", "t,p", MATCH_BGE, MASK_BGE | MASK_RS1, match_opcode, INSN_ALIAS|RD_xs2 },
+{"bgez", "I", "s,p", MATCH_BGE, MASK_BGE | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
+{"ble", "I", "t,s,p", MATCH_BGE, MASK_BGE, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
+{"bleu", "I", "t,s,p", MATCH_BGEU, MASK_BGEU, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
+{"bge", "I", "s,t,p", MATCH_BGE, MASK_BGE, match_opcode, RD_xs1|RD_xs2 },
+{"bgeu", "I", "s,t,p", MATCH_BGEU, MASK_BGEU, match_opcode, RD_xs1|RD_xs2 },
+{"bltz", "I", "s,p", MATCH_BLT, MASK_BLT | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
+{"bgtz", "I", "t,p", MATCH_BLT, MASK_BLT | MASK_RS1, match_opcode, INSN_ALIAS|RD_xs2 },
+{"blt", "I", "s,t,p", MATCH_BLT, MASK_BLT, match_opcode, RD_xs1|RD_xs2 },
+{"bltu", "I", "s,t,p", MATCH_BLTU, MASK_BLTU, match_opcode, RD_xs1|RD_xs2 },
+{"bgt", "I", "t,s,p", MATCH_BLT, MASK_BLT, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
+{"bgtu", "I", "t,s,p", MATCH_BLTU, MASK_BLTU, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
+{"bnez", "I", "s,p", MATCH_BNE, MASK_BNE | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
+{"bne", "I", "s,t,p", MATCH_BNE, MASK_BNE, match_opcode, RD_xs1|RD_xs2 },
+{"addi", "I", "d,s,j", MATCH_ADDI, MASK_ADDI, match_opcode, WR_xd|RD_xs1 },
+{"add", "I", "d,s,t", MATCH_ADD, MASK_ADD, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"add", "I", "d,s,t,0",MATCH_ADD, MASK_ADD, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"add", "I", "d,s,j", MATCH_ADDI, MASK_ADDI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"la", "I", "d,A", 0, (int) M_LA, match_never, INSN_MACRO },
+{"lla", "I", "d,A", 0, (int) M_LLA, match_never, INSN_MACRO },
+{"la.tls.gd", "I", "d,A", 0, (int) M_LA_TLS_GD, match_never, INSN_MACRO },
+{"la.tls.ie", "I", "d,A", 0, (int) M_LA_TLS_IE, match_never, INSN_MACRO },
+{"neg", "I", "d,t", MATCH_SUB, MASK_SUB | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 }, /* sub 0 */
+{"slli", "I", "d,s,>", MATCH_SLLI, MASK_SLLI, match_opcode, WR_xd|RD_xs1 },
+{"sll", "I", "d,s,t", MATCH_SLL, MASK_SLL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"sll", "I", "d,s,>", MATCH_SLLI, MASK_SLLI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"srli", "I", "d,s,>", MATCH_SRLI, MASK_SRLI, match_opcode, WR_xd|RD_xs1 },
+{"srl", "I", "d,s,t", MATCH_SRL, MASK_SRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"srl", "I", "d,s,>", MATCH_SRLI, MASK_SRLI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"srai", "I", "d,s,>", MATCH_SRAI, MASK_SRAI, match_opcode, WR_xd|RD_xs1 },
+{"sra", "I", "d,s,t", MATCH_SRA, MASK_SRA, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"sra", "I", "d,s,>", MATCH_SRAI, MASK_SRAI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"sub", "I", "d,s,t", MATCH_SUB, MASK_SUB, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"ret", "I", "", MATCH_JALR | (LINK_REG << OP_SH_RS1), MASK_JALR | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"j", "I", "a", MATCH_JAL, MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS },
+{"jal", "I", "a", MATCH_JAL | (LINK_REG << OP_SH_RD), MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS|WR_xd },
+{"jal", "I", "d,a", MATCH_JAL, MASK_JAL, match_opcode, WR_xd },
+{"call", "I", "c", 0, (int) M_CALL, match_never, INSN_MACRO },
+{"jump", "I", "c", 0, (int) M_JUMP, match_never, INSN_MACRO },
+{"jr", "I", "s", MATCH_JALR, MASK_JALR | MASK_RD | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"jr", "I", "s,j", MATCH_JALR, MASK_JALR | MASK_RD, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"jalr", "I", "s", MATCH_JALR | (LINK_REG << OP_SH_RD), MASK_JALR | MASK_RD | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"jalr", "I", "s,j", MATCH_JALR | (LINK_REG << OP_SH_RD), MASK_JALR | MASK_RD, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"jalr", "I", "d,s", MATCH_JALR, MASK_JALR | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"jalr", "I", "d,s,j", MATCH_JALR, MASK_JALR, match_opcode, WR_xd|RD_xs1 },
+{"lb", "I", "d,o(s)", MATCH_LB, MASK_LB, match_opcode, WR_xd|RD_xs1 },
+{"lb", "I", "d,A", 0, (int) M_LB, match_never, INSN_MACRO },
+{"lbu", "I", "d,o(s)", MATCH_LBU, MASK_LBU, match_opcode, WR_xd|RD_xs1 },
+{"lbu", "I", "d,A", 0, (int) M_LBU, match_never, INSN_MACRO },
+{"lh", "I", "d,o(s)", MATCH_LH, MASK_LH, match_opcode, WR_xd|RD_xs1 },
+{"lh", "I", "d,A", 0, (int) M_LH, match_never, INSN_MACRO },
+{"lhu", "I", "d,o(s)", MATCH_LHU, MASK_LHU, match_opcode, WR_xd|RD_xs1 },
+{"lhu", "I", "d,A", 0, (int) M_LHU, match_never, INSN_MACRO },
+{"lw", "I", "d,o(s)", MATCH_LW, MASK_LW, match_opcode, WR_xd|RD_xs1 },
+{"lw", "I", "d,A", 0, (int) M_LW, match_never, INSN_MACRO },
+{"lui", "I", "d,u", MATCH_LUI, MASK_LUI, match_opcode, WR_xd },
+{"not", "I", "d,s", MATCH_XORI | MASK_IMM, MASK_XORI | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"ori", "I", "d,s,j", MATCH_ORI, MASK_ORI, match_opcode, WR_xd|RD_xs1 },
+{"or", "I", "d,s,t", MATCH_OR, MASK_OR, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"or", "I", "d,s,j", MATCH_ORI, MASK_ORI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"auipc", "I", "d,u", MATCH_AUIPC, MASK_AUIPC, match_opcode, WR_xd },
+{"seqz", "I", "d,s", MATCH_SLTIU | ENCODE_ITYPE_IMM(1), MASK_SLTIU | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"snez", "I", "d,t", MATCH_SLTU, MASK_SLTU | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 },
+{"sltz", "I", "d,s", MATCH_SLT, MASK_SLT | MASK_RS2, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"sgtz", "I", "d,t", MATCH_SLT, MASK_SLT | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 },
+{"slti", "I", "d,s,j", MATCH_SLTI, MASK_SLTI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"slt", "I", "d,s,t", MATCH_SLT, MASK_SLT, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"slt", "I", "d,s,j", MATCH_SLTI, MASK_SLTI, match_opcode, WR_xd|RD_xs1 },
+{"sltiu", "I", "d,s,j", MATCH_SLTIU, MASK_SLTIU, match_opcode, WR_xd|RD_xs1 },
+{"sltu", "I", "d,s,t", MATCH_SLTU, MASK_SLTU, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"sltu", "I", "d,s,j", MATCH_SLTIU, MASK_SLTIU, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"sgt", "I", "d,t,s", MATCH_SLT, MASK_SLT, match_opcode, INSN_ALIAS|WR_xd|RD_xs1|RD_xs2 },
+{"sgtu", "I", "d,t,s", MATCH_SLTU, MASK_SLTU, match_opcode, INSN_ALIAS|WR_xd|RD_xs1|RD_xs2 },
+{"sb", "I", "t,q(s)", MATCH_SB, MASK_SB, match_opcode, RD_xs1|RD_xs2 },
+{"sb", "I", "t,A,s", 0, (int) M_SB, match_never, INSN_MACRO },
+{"sh", "I", "t,q(s)", MATCH_SH, MASK_SH, match_opcode, RD_xs1|RD_xs2 },
+{"sh", "I", "t,A,s", 0, (int) M_SH, match_never, INSN_MACRO },
+{"sw", "I", "t,q(s)", MATCH_SW, MASK_SW, match_opcode, RD_xs1|RD_xs2 },
+{"sw", "I", "t,A,s", 0, (int) M_SW, match_never, INSN_MACRO },
+{"fence", "I", "", MATCH_FENCE | MASK_PRED | MASK_SUCC, MASK_FENCE | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS },
+{"fence", "I", "P,Q", MATCH_FENCE, MASK_FENCE | MASK_RD | MASK_RS1 | (MASK_IMM & ~MASK_PRED & ~MASK_SUCC), match_opcode, 0 },
+{"fence.i", "I", "", MATCH_FENCE_I, MASK_FENCE | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, 0 },
+{"rdcycle", "I", "d", MATCH_RDCYCLE, MASK_RDCYCLE, match_opcode, WR_xd },
+{"rdinstret", "I", "d", MATCH_RDINSTRET, MASK_RDINSTRET, match_opcode, WR_xd },
+{"rdtime", "I", "d", MATCH_RDTIME, MASK_RDTIME, match_opcode, WR_xd },
+{"rdcycleh", "32I", "d", MATCH_RDCYCLEH, MASK_RDCYCLEH, match_opcode, WR_xd },
+{"rdinstreth","32I", "d", MATCH_RDINSTRETH, MASK_RDINSTRETH, match_opcode, WR_xd },
+{"rdtimeh", "32I", "d", MATCH_RDTIMEH, MASK_RDTIMEH, match_opcode, WR_xd },
+{"sbreak", "I", "", MATCH_SBREAK, MASK_SBREAK, match_opcode, 0 },
+{"scall", "I", "", MATCH_SCALL, MASK_SCALL, match_opcode, 0 },
+{"xori", "I", "d,s,j", MATCH_XORI, MASK_XORI, match_opcode, WR_xd|RD_xs1 },
+{"xor", "I", "d,s,t", MATCH_XOR, MASK_XOR, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"xor", "I", "d,s,j", MATCH_XORI, MASK_XORI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"lwu", "64I", "d,o(s)", MATCH_LWU, MASK_LWU, match_opcode, WR_xd|RD_xs1 },
+{"lwu", "64I", "d,A", 0, (int) M_LWU, match_never, INSN_MACRO },
+{"ld", "64I", "d,o(s)", MATCH_LD, MASK_LD, match_opcode, WR_xd|RD_xs1 },
+{"ld", "64I", "d,A", 0, (int) M_LD, match_never, INSN_MACRO },
+{"sd", "64I", "t,q(s)", MATCH_SD, MASK_SD, match_opcode, RD_xs1|RD_xs2 },
+{"sd", "64I", "t,A,s", 0, (int) M_SD, match_never, INSN_MACRO },
+{"sext.w", "64I", "d,s", MATCH_ADDIW, MASK_ADDIW | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"addiw", "64I", "d,s,j", MATCH_ADDIW, MASK_ADDIW, match_opcode, WR_xd|RD_xs1 },
+{"addw", "64I", "d,s,t", MATCH_ADDW, MASK_ADDW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"addw", "64I", "d,s,j", MATCH_ADDIW, MASK_ADDIW, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"negw", "64I", "d,t", MATCH_SUBW, MASK_SUBW | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 }, /* sub 0 */
+{"slliw", "64I", "d,s,<", MATCH_SLLIW, MASK_SLLIW, match_opcode, WR_xd|RD_xs1 },
+{"sllw", "64I", "d,s,t", MATCH_SLLW, MASK_SLLW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"sllw", "64I", "d,s,<", MATCH_SLLIW, MASK_SLLIW, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"srliw", "64I", "d,s,<", MATCH_SRLIW, MASK_SRLIW, match_opcode, WR_xd|RD_xs1 },
+{"srlw", "64I", "d,s,t", MATCH_SRLW, MASK_SRLW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"srlw", "64I", "d,s,<", MATCH_SRLIW, MASK_SRLIW, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"sraiw", "64I", "d,s,<", MATCH_SRAIW, MASK_SRAIW, match_opcode, WR_xd|RD_xs1 },
+{"sraw", "64I", "d,s,t", MATCH_SRAW, MASK_SRAW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"sraw", "64I", "d,s,<", MATCH_SRAIW, MASK_SRAIW, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"subw", "64I", "d,s,t", MATCH_SUBW, MASK_SUBW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+
+/* Atomic memory operation instruction subset */
+{"lr.w", "A", "d,0(s)", MATCH_LR_W, MASK_LR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.w", "A", "d,t,0(s)", MATCH_SC_W, MASK_SC_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.w", "A", "d,t,0(s)", MATCH_AMOADD_W, MASK_AMOADD_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.w", "A", "d,t,0(s)", MATCH_AMOSWAP_W, MASK_AMOSWAP_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.w", "A", "d,t,0(s)", MATCH_AMOAND_W, MASK_AMOAND_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.w", "A", "d,t,0(s)", MATCH_AMOOR_W, MASK_AMOOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.w", "A", "d,t,0(s)", MATCH_AMOXOR_W, MASK_AMOXOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.w", "A", "d,t,0(s)", MATCH_AMOMAX_W, MASK_AMOMAX_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.w", "A", "d,t,0(s)", MATCH_AMOMAXU_W, MASK_AMOMAXU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.w", "A", "d,t,0(s)", MATCH_AMOMIN_W, MASK_AMOMIN_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.w", "A", "d,t,0(s)", MATCH_AMOMINU_W, MASK_AMOMINU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.w.aq", "A", "d,0(s)", MATCH_LR_W | MASK_AQ, MASK_LR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.w.aq", "A", "d,t,0(s)", MATCH_SC_W | MASK_AQ, MASK_SC_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.w.aq", "A", "d,t,0(s)", MATCH_AMOADD_W | MASK_AQ, MASK_AMOADD_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.w.aq", "A", "d,t,0(s)", MATCH_AMOSWAP_W | MASK_AQ, MASK_AMOSWAP_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.w.aq", "A", "d,t,0(s)", MATCH_AMOAND_W | MASK_AQ, MASK_AMOAND_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.w.aq", "A", "d,t,0(s)", MATCH_AMOOR_W | MASK_AQ, MASK_AMOOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.w.aq", "A", "d,t,0(s)", MATCH_AMOXOR_W | MASK_AQ, MASK_AMOXOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.w.aq", "A", "d,t,0(s)", MATCH_AMOMAX_W | MASK_AQ, MASK_AMOMAX_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.w.aq", "A", "d,t,0(s)", MATCH_AMOMAXU_W | MASK_AQ, MASK_AMOMAXU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.w.aq", "A", "d,t,0(s)", MATCH_AMOMIN_W | MASK_AQ, MASK_AMOMIN_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.w.aq", "A", "d,t,0(s)", MATCH_AMOMINU_W | MASK_AQ, MASK_AMOMINU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.w.rl", "A", "d,0(s)", MATCH_LR_W | MASK_RL, MASK_LR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.w.rl", "A", "d,t,0(s)", MATCH_SC_W | MASK_RL, MASK_SC_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.w.rl", "A", "d,t,0(s)", MATCH_AMOADD_W | MASK_RL, MASK_AMOADD_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.w.rl", "A", "d,t,0(s)", MATCH_AMOSWAP_W | MASK_RL, MASK_AMOSWAP_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.w.rl", "A", "d,t,0(s)", MATCH_AMOAND_W | MASK_RL, MASK_AMOAND_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.w.rl", "A", "d,t,0(s)", MATCH_AMOOR_W | MASK_RL, MASK_AMOOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.w.rl", "A", "d,t,0(s)", MATCH_AMOXOR_W | MASK_RL, MASK_AMOXOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.w.rl", "A", "d,t,0(s)", MATCH_AMOMAX_W | MASK_RL, MASK_AMOMAX_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.w.rl", "A", "d,t,0(s)", MATCH_AMOMAXU_W | MASK_RL, MASK_AMOMAXU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.w.rl", "A", "d,t,0(s)", MATCH_AMOMIN_W | MASK_RL, MASK_AMOMIN_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.w.rl", "A", "d,t,0(s)", MATCH_AMOMINU_W | MASK_RL, MASK_AMOMINU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.w.sc", "A", "d,0(s)", MATCH_LR_W | MASK_AQRL, MASK_LR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.w.sc", "A", "d,t,0(s)", MATCH_SC_W | MASK_AQRL, MASK_SC_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.w.sc", "A", "d,t,0(s)", MATCH_AMOADD_W | MASK_AQRL, MASK_AMOADD_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.w.sc", "A", "d,t,0(s)", MATCH_AMOSWAP_W | MASK_AQRL, MASK_AMOSWAP_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.w.sc", "A", "d,t,0(s)", MATCH_AMOAND_W | MASK_AQRL, MASK_AMOAND_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.w.sc", "A", "d,t,0(s)", MATCH_AMOOR_W | MASK_AQRL, MASK_AMOOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.w.sc", "A", "d,t,0(s)", MATCH_AMOXOR_W | MASK_AQRL, MASK_AMOXOR_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.w.sc", "A", "d,t,0(s)", MATCH_AMOMAX_W | MASK_AQRL, MASK_AMOMAX_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.w.sc", "A", "d,t,0(s)", MATCH_AMOMAXU_W | MASK_AQRL, MASK_AMOMAXU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.w.sc", "A", "d,t,0(s)", MATCH_AMOMIN_W | MASK_AQRL, MASK_AMOMIN_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.w.sc", "A", "d,t,0(s)", MATCH_AMOMINU_W | MASK_AQRL, MASK_AMOMINU_W | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.d", "64A", "d,0(s)", MATCH_LR_D, MASK_LR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.d", "64A", "d,t,0(s)", MATCH_SC_D, MASK_SC_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.d", "64A", "d,t,0(s)", MATCH_AMOADD_D, MASK_AMOADD_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.d", "64A", "d,t,0(s)", MATCH_AMOSWAP_D, MASK_AMOSWAP_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.d", "64A", "d,t,0(s)", MATCH_AMOAND_D, MASK_AMOAND_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.d", "64A", "d,t,0(s)", MATCH_AMOOR_D, MASK_AMOOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.d", "64A", "d,t,0(s)", MATCH_AMOXOR_D, MASK_AMOXOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.d", "64A", "d,t,0(s)", MATCH_AMOMAX_D, MASK_AMOMAX_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.d", "64A", "d,t,0(s)", MATCH_AMOMAXU_D, MASK_AMOMAXU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.d", "64A", "d,t,0(s)", MATCH_AMOMIN_D, MASK_AMOMIN_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.d", "64A", "d,t,0(s)", MATCH_AMOMINU_D, MASK_AMOMINU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.d.aq", "64A", "d,0(s)", MATCH_LR_D | MASK_AQ, MASK_LR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.d.aq", "64A", "d,t,0(s)", MATCH_SC_D | MASK_AQ, MASK_SC_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.d.aq", "64A", "d,t,0(s)", MATCH_AMOADD_D | MASK_AQ, MASK_AMOADD_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.d.aq", "64A", "d,t,0(s)", MATCH_AMOSWAP_D | MASK_AQ, MASK_AMOSWAP_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.d.aq", "64A", "d,t,0(s)", MATCH_AMOAND_D | MASK_AQ, MASK_AMOAND_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.d.aq", "64A", "d,t,0(s)", MATCH_AMOOR_D | MASK_AQ, MASK_AMOOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.d.aq", "64A", "d,t,0(s)", MATCH_AMOXOR_D | MASK_AQ, MASK_AMOXOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.d.aq", "64A", "d,t,0(s)", MATCH_AMOMAX_D | MASK_AQ, MASK_AMOMAX_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.d.aq", "64A", "d,t,0(s)", MATCH_AMOMAXU_D | MASK_AQ, MASK_AMOMAXU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.d.aq", "64A", "d,t,0(s)", MATCH_AMOMIN_D | MASK_AQ, MASK_AMOMIN_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.d.aq", "64A", "d,t,0(s)", MATCH_AMOMINU_D | MASK_AQ, MASK_AMOMINU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.d.rl", "64A", "d,0(s)", MATCH_LR_D | MASK_RL, MASK_LR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.d.rl", "64A", "d,t,0(s)", MATCH_SC_D | MASK_RL, MASK_SC_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.d.rl", "64A", "d,t,0(s)", MATCH_AMOADD_D | MASK_RL, MASK_AMOADD_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.d.rl", "64A", "d,t,0(s)", MATCH_AMOSWAP_D | MASK_RL, MASK_AMOSWAP_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.d.rl", "64A", "d,t,0(s)", MATCH_AMOAND_D | MASK_RL, MASK_AMOAND_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.d.rl", "64A", "d,t,0(s)", MATCH_AMOOR_D | MASK_RL, MASK_AMOOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.d.rl", "64A", "d,t,0(s)", MATCH_AMOXOR_D | MASK_RL, MASK_AMOXOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.d.rl", "64A", "d,t,0(s)", MATCH_AMOMAX_D | MASK_RL, MASK_AMOMAX_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.d.rl", "64A", "d,t,0(s)", MATCH_AMOMAXU_D | MASK_RL, MASK_AMOMAXU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.d.rl", "64A", "d,t,0(s)", MATCH_AMOMIN_D | MASK_RL, MASK_AMOMIN_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.d.rl", "64A", "d,t,0(s)", MATCH_AMOMINU_D | MASK_RL, MASK_AMOMINU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"lr.d.sc", "64A", "d,0(s)", MATCH_LR_D | MASK_AQRL, MASK_LR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1 },
+{"sc.d.sc", "64A", "d,t,0(s)", MATCH_SC_D | MASK_AQRL, MASK_SC_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoadd.d.sc", "64A", "d,t,0(s)", MATCH_AMOADD_D | MASK_AQRL, MASK_AMOADD_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoswap.d.sc", "64A", "d,t,0(s)", MATCH_AMOSWAP_D | MASK_AQRL, MASK_AMOSWAP_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoand.d.sc", "64A", "d,t,0(s)", MATCH_AMOAND_D | MASK_AQRL, MASK_AMOAND_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoor.d.sc", "64A", "d,t,0(s)", MATCH_AMOOR_D | MASK_AQRL, MASK_AMOOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amoxor.d.sc", "64A", "d,t,0(s)", MATCH_AMOXOR_D | MASK_AQRL, MASK_AMOXOR_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomax.d.sc", "64A", "d,t,0(s)", MATCH_AMOMAX_D | MASK_AQRL, MASK_AMOMAX_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomaxu.d.sc", "64A", "d,t,0(s)", MATCH_AMOMAXU_D | MASK_AQRL, MASK_AMOMAXU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amomin.d.sc", "64A", "d,t,0(s)", MATCH_AMOMIN_D | MASK_AQRL, MASK_AMOMIN_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"amominu.d.sc", "64A", "d,t,0(s)", MATCH_AMOMINU_D | MASK_AQRL, MASK_AMOMINU_D | MASK_AQRL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+
+/* Multiply/Divide instruction subset */
+{"mul", "M", "d,s,t", MATCH_MUL, MASK_MUL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"mulh", "M", "d,s,t", MATCH_MULH, MASK_MULH, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"mulhu", "M", "d,s,t", MATCH_MULHU, MASK_MULHU, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"mulhsu", "M", "d,s,t", MATCH_MULHSU, MASK_MULHSU, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"div", "M", "d,s,t", MATCH_DIV, MASK_DIV, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"divu", "M", "d,s,t", MATCH_DIVU, MASK_DIVU, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"rem", "M", "d,s,t", MATCH_REM, MASK_REM, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"remu", "M", "d,s,t", MATCH_REMU, MASK_REMU, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"mulw", "64M", "d,s,t", MATCH_MULW, MASK_MULW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"divw", "64M", "d,s,t", MATCH_DIVW, MASK_DIVW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"divuw", "64M", "d,s,t", MATCH_DIVUW, MASK_DIVUW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"remw", "64M", "d,s,t", MATCH_REMW, MASK_REMW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"remuw", "64M", "d,s,t", MATCH_REMUW, MASK_REMUW, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+
+/* Single-precision floating-point instruction subset */
+{"frsr", "F", "d", MATCH_FRCSR, MASK_FRCSR, match_opcode, WR_xd },
+{"fssr", "F", "s", MATCH_FSCSR, MASK_FSCSR | MASK_RD, match_opcode, RD_xs1 },
+{"fssr", "F", "d,s", MATCH_FSCSR, MASK_FSCSR, match_opcode, WR_xd|RD_xs1 },
+{"frcsr", "F", "d", MATCH_FRCSR, MASK_FRCSR, match_opcode, WR_xd },
+{"fscsr", "F", "s", MATCH_FSCSR, MASK_FSCSR | MASK_RD, match_opcode, RD_xs1 },
+{"fscsr", "F", "d,s", MATCH_FSCSR, MASK_FSCSR, match_opcode, WR_xd|RD_xs1 },
+{"frrm", "F", "d", MATCH_FRRM, MASK_FRRM, match_opcode, WR_xd },
+{"fsrm", "F", "s", MATCH_FSRM, MASK_FSRM | MASK_RD, match_opcode, RD_xs1 },
+{"fsrm", "F", "d,s", MATCH_FSRM, MASK_FSRM, match_opcode, WR_xd|RD_xs1 },
+{"frflags", "F", "d", MATCH_FRFLAGS, MASK_FRFLAGS, match_opcode, WR_xd },
+{"fsflags", "F", "s", MATCH_FSFLAGS, MASK_FSFLAGS | MASK_RD, match_opcode, RD_xs1 },
+{"fsflags", "F", "d,s", MATCH_FSFLAGS, MASK_FSFLAGS, match_opcode, WR_xd|RD_xs1 },
+{"flw", "F", "D,o(s)", MATCH_FLW, MASK_FLW, match_opcode, WR_fd|RD_xs1 },
+{"flw", "F", "D,A,s", 0, (int) M_FLW, match_never, INSN_MACRO },
+{"fsw", "F", "T,q(s)", MATCH_FSW, MASK_FSW, match_opcode, RD_xs1|RD_fs2 },
+{"fsw", "F", "T,A,s", 0, (int) M_FSW, match_never, INSN_MACRO },
+{"fmv.x.s", "F", "d,S", MATCH_FMV_X_S, MASK_FMV_X_S, match_opcode, WR_xd|RD_fs1 },
+{"fmv.s.x", "F", "D,s", MATCH_FMV_S_X, MASK_FMV_S_X, match_opcode, WR_fd|RD_xs1 },
+{"fmv.s", "F", "D,U", MATCH_FSGNJ_S, MASK_FSGNJ_S, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fneg.s", "F", "D,U", MATCH_FSGNJN_S, MASK_FSGNJN_S, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fabs.s", "F", "D,U", MATCH_FSGNJX_S, MASK_FSGNJX_S, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fsgnj.s", "F", "D,S,T", MATCH_FSGNJ_S, MASK_FSGNJ_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjn.s", "F", "D,S,T", MATCH_FSGNJN_S, MASK_FSGNJN_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjx.s", "F", "D,S,T", MATCH_FSGNJX_S, MASK_FSGNJX_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.s", "F", "D,S,T", MATCH_FADD_S | MASK_RM, MASK_FADD_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.s", "F", "D,S,T,m", MATCH_FADD_S, MASK_FADD_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.s", "F", "D,S,T", MATCH_FSUB_S | MASK_RM, MASK_FSUB_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.s", "F", "D,S,T,m", MATCH_FSUB_S, MASK_FSUB_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.s", "F", "D,S,T", MATCH_FMUL_S | MASK_RM, MASK_FMUL_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.s", "F", "D,S,T,m", MATCH_FMUL_S, MASK_FMUL_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.s", "F", "D,S,T", MATCH_FDIV_S | MASK_RM, MASK_FDIV_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.s", "F", "D,S,T,m", MATCH_FDIV_S, MASK_FDIV_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsqrt.s", "F", "D,S", MATCH_FSQRT_S | MASK_RM, MASK_FSQRT_S | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fsqrt.s", "F", "D,S,m", MATCH_FSQRT_S, MASK_FSQRT_S, match_opcode, WR_fd|RD_fs1 },
+{"fmin.s", "F", "D,S,T", MATCH_FMIN_S, MASK_FMIN_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmax.s", "F", "D,S,T", MATCH_FMAX_S, MASK_FMAX_S, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmadd.s", "F", "D,S,T,R", MATCH_FMADD_S | MASK_RM, MASK_FMADD_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmadd.s", "F", "D,S,T,R,m", MATCH_FMADD_S, MASK_FMADD_S, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.s", "F", "D,S,T,R", MATCH_FNMADD_S | MASK_RM, MASK_FNMADD_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.s", "F", "D,S,T,R,m", MATCH_FNMADD_S, MASK_FNMADD_S, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.s", "F", "D,S,T,R", MATCH_FMSUB_S | MASK_RM, MASK_FMSUB_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.s", "F", "D,S,T,R,m", MATCH_FMSUB_S, MASK_FMSUB_S, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.s", "F", "D,S,T,R", MATCH_FNMSUB_S | MASK_RM, MASK_FNMSUB_S | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.s", "F", "D,S,T,R,m", MATCH_FNMSUB_S, MASK_FNMSUB_S, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fcvt.w.s", "F", "d,S", MATCH_FCVT_W_S | MASK_RM, MASK_FCVT_W_S | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.w.s", "F", "d,S,m", MATCH_FCVT_W_S, MASK_FCVT_W_S, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.s", "F", "d,S", MATCH_FCVT_WU_S | MASK_RM, MASK_FCVT_WU_S | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.s", "F", "d,S,m", MATCH_FCVT_WU_S, MASK_FCVT_WU_S, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.s.w", "F", "D,s", MATCH_FCVT_S_W | MASK_RM, MASK_FCVT_S_W | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.w", "F", "D,s,m", MATCH_FCVT_S_W, MASK_FCVT_S_W, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.wu", "F", "D,s", MATCH_FCVT_S_WU | MASK_RM, MASK_FCVT_S_W | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.wu", "F", "D,s,m", MATCH_FCVT_S_WU, MASK_FCVT_S_WU, match_opcode, WR_fd|RD_xs1 },
+{"fclass.s", "F", "d,S", MATCH_FCLASS_S, MASK_FCLASS_S, match_opcode, WR_xd|RD_fs1 },
+{"feq.s", "F", "d,S,T", MATCH_FEQ_S, MASK_FEQ_S, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"flt.s", "F", "d,S,T", MATCH_FLT_S, MASK_FLT_S, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fle.s", "F", "d,S,T", MATCH_FLE_S, MASK_FLE_S, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fgt.s", "F", "d,T,S", MATCH_FLT_S, MASK_FLT_S, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fge.s", "F", "d,T,S", MATCH_FLE_S, MASK_FLE_S, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fcvt.l.s", "64F", "d,S", MATCH_FCVT_L_S | MASK_RM, MASK_FCVT_L_S | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.l.s", "64F", "d,S,m", MATCH_FCVT_L_S, MASK_FCVT_L_S, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.s", "64F", "d,S", MATCH_FCVT_LU_S | MASK_RM, MASK_FCVT_LU_S | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.s", "64F", "d,S,m", MATCH_FCVT_LU_S, MASK_FCVT_LU_S, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.s.l", "64F", "D,s", MATCH_FCVT_S_L | MASK_RM, MASK_FCVT_S_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.l", "64F", "D,s,m", MATCH_FCVT_S_L, MASK_FCVT_S_L, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.lu", "64F", "D,s", MATCH_FCVT_S_LU | MASK_RM, MASK_FCVT_S_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.s.lu", "64F", "D,s,m", MATCH_FCVT_S_LU, MASK_FCVT_S_LU, match_opcode, WR_fd|RD_xs1 },
+
+/* Double-precision floating-point instruction subset */
+{"fld", "D", "D,o(s)", MATCH_FLD, MASK_FLD, match_opcode, WR_fd|RD_xs1 },
+{"fld", "D", "D,A,s", 0, (int) M_FLD, match_never, INSN_MACRO },
+{"fsd", "D", "T,q(s)", MATCH_FSD, MASK_FSD, match_opcode, RD_xs1|RD_fs2 },
+{"fsd", "D", "T,A,s", 0, (int) M_FSD, match_never, INSN_MACRO },
+{"fmv.d", "D", "D,U", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fneg.d", "D", "D,U", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fabs.d", "D", "D,U", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_rs1_eq_rs2, INSN_ALIAS|WR_fd|RD_fs1|RD_fs2 },
+{"fsgnj.d", "D", "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjn.d", "D", "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjx.d", "D", "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.d", "D", "D,S,T", MATCH_FADD_D | MASK_RM, MASK_FADD_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.d", "D", "D,S,T,m", MATCH_FADD_D, MASK_FADD_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.d", "D", "D,S,T", MATCH_FSUB_D | MASK_RM, MASK_FSUB_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.d", "D", "D,S,T,m", MATCH_FSUB_D, MASK_FSUB_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.d", "D", "D,S,T", MATCH_FMUL_D | MASK_RM, MASK_FMUL_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.d", "D", "D,S,T,m", MATCH_FMUL_D, MASK_FMUL_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.d", "D", "D,S,T", MATCH_FDIV_D | MASK_RM, MASK_FDIV_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.d", "D", "D,S,T,m", MATCH_FDIV_D, MASK_FDIV_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsqrt.d", "D", "D,S", MATCH_FSQRT_D | MASK_RM, MASK_FSQRT_D | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fsqrt.d", "D", "D,S,m", MATCH_FSQRT_D, MASK_FSQRT_D, match_opcode, WR_fd|RD_fs1 },
+{"fmin.d", "D", "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmax.d", "D", "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmadd.d", "D", "D,S,T,R", MATCH_FMADD_D | MASK_RM, MASK_FMADD_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmadd.d", "D", "D,S,T,R,m", MATCH_FMADD_D, MASK_FMADD_D, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.d", "D", "D,S,T,R", MATCH_FNMADD_D | MASK_RM, MASK_FNMADD_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.d", "D", "D,S,T,R,m", MATCH_FNMADD_D, MASK_FNMADD_D, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.d", "D", "D,S,T,R", MATCH_FMSUB_D | MASK_RM, MASK_FMSUB_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.d", "D", "D,S,T,R,m", MATCH_FMSUB_D, MASK_FMSUB_D, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.d", "D", "D,S,T,R", MATCH_FNMSUB_D | MASK_RM, MASK_FNMSUB_D | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.d", "D", "D,S,T,R,m", MATCH_FNMSUB_D, MASK_FNMSUB_D, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fcvt.w.d", "D", "d,S", MATCH_FCVT_W_D | MASK_RM, MASK_FCVT_W_D | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.w.d", "D", "d,S,m", MATCH_FCVT_W_D, MASK_FCVT_W_D, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.d", "D", "d,S", MATCH_FCVT_WU_D | MASK_RM, MASK_FCVT_WU_D | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.d", "D", "d,S,m", MATCH_FCVT_WU_D, MASK_FCVT_WU_D, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.d.w", "D", "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.d.wu", "D", "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.d.s", "D", "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.s.d", "D", "D,S", MATCH_FCVT_S_D | MASK_RM, MASK_FCVT_S_D | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.s.d", "D", "D,S,m", MATCH_FCVT_S_D, MASK_FCVT_S_D, match_opcode, WR_fd|RD_fs1 },
+{"fclass.d", "D", "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, match_opcode, WR_xd|RD_fs1 },
+{"feq.d", "D", "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"flt.d", "D", "d,S,T", MATCH_FLT_D, MASK_FLT_D, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fle.d", "D", "d,S,T", MATCH_FLE_D, MASK_FLE_D, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fgt.d", "D", "d,T,S", MATCH_FLT_D, MASK_FLT_D, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fge.d", "D", "d,T,S", MATCH_FLE_D, MASK_FLE_D, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fmv.x.d", "64D", "d,S", MATCH_FMV_X_D, MASK_FMV_X_D, match_opcode, WR_xd|RD_fs1 },
+{"fmv.d.x", "64D", "D,s", MATCH_FMV_D_X, MASK_FMV_D_X, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.l.d", "64D", "d,S", MATCH_FCVT_L_D | MASK_RM, MASK_FCVT_L_D | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.l.d", "64D", "d,S,m", MATCH_FCVT_L_D, MASK_FCVT_L_D, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.d", "64D", "d,S", MATCH_FCVT_LU_D | MASK_RM, MASK_FCVT_LU_D | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.d", "64D", "d,S,m", MATCH_FCVT_LU_D, MASK_FCVT_LU_D, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.d.l", "64D", "D,s", MATCH_FCVT_D_L | MASK_RM, MASK_FCVT_D_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.d.l", "64D", "D,s,m", MATCH_FCVT_D_L, MASK_FCVT_D_L, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.d.lu", "64D", "D,s", MATCH_FCVT_D_LU | MASK_RM, MASK_FCVT_D_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.d.lu", "64D", "D,s,m", MATCH_FCVT_D_LU, MASK_FCVT_D_LU, match_opcode, WR_fd|RD_xs1 },
+
+/* Supervisor instructions */
+{"csrr", "I", "d,E", MATCH_CSRRS, MASK_CSRRS | MASK_RS1, match_opcode, WR_xd },
+{"csrwi", "I", "E,Z", MATCH_CSRRWI, MASK_CSRRWI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrw", "I", "E,s", MATCH_CSRRW, MASK_CSRRW | MASK_RD, match_opcode, RD_xs1 },
+{"csrw", "I", "E,Z", MATCH_CSRRWI, MASK_CSRRWI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrsi", "I", "E,Z", MATCH_CSRRSI, MASK_CSRRSI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrs", "I", "E,s", MATCH_CSRRS, MASK_CSRRS | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrs", "I", "E,Z", MATCH_CSRRSI, MASK_CSRRSI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrci", "I", "E,Z", MATCH_CSRRCI, MASK_CSRRCI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrc", "I", "E,s", MATCH_CSRRC, MASK_CSRRC | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrc", "I", "E,Z", MATCH_CSRRCI, MASK_CSRRCI | MASK_RD, match_opcode, WR_xd|RD_xs1 },
+{"csrrw", "I", "d,E,s", MATCH_CSRRW, MASK_CSRRW, match_opcode, WR_xd|RD_xs1 },
+{"csrrw", "I", "d,E,Z", MATCH_CSRRWI, MASK_CSRRWI, match_opcode, WR_xd|RD_xs1 },
+{"csrrs", "I", "d,E,s", MATCH_CSRRS, MASK_CSRRS, match_opcode, WR_xd|RD_xs1 },
+{"csrrs", "I", "d,E,Z", MATCH_CSRRSI, MASK_CSRRSI, match_opcode, WR_xd|RD_xs1 },
+{"csrrc", "I", "d,E,s", MATCH_CSRRC, MASK_CSRRC, match_opcode, WR_xd|RD_xs1 },
+{"csrrc", "I", "d,E,Z", MATCH_CSRRCI, MASK_CSRRCI, match_opcode, WR_xd|RD_xs1 },
+{"csrrwi", "I", "d,E,Z", MATCH_CSRRWI, MASK_CSRRWI, match_opcode, WR_xd|RD_xs1 },
+{"csrrsi", "I", "d,E,Z", MATCH_CSRRSI, MASK_CSRRSI, match_opcode, WR_xd|RD_xs1 },
+{"csrrci", "I", "d,E,Z", MATCH_CSRRCI, MASK_CSRRCI, match_opcode, WR_xd|RD_xs1 },
+{"sret", "I", "", MATCH_SRET, MASK_SRET, match_opcode, 0 },
+
+/* Half-precision floating-point instruction subset */
+{"flh", "Xhwacha", "D,o(s)", MATCH_FLH, MASK_FLH, match_opcode, WR_fd|RD_xs1 },
+{"fsh", "Xhwacha", "T,q(s)", MATCH_FSH, MASK_FSH, match_opcode, RD_xs1|RD_fs2 },
+{"fsgnj.h", "Xhwacha", "D,S,T", MATCH_FSGNJ_H, MASK_FSGNJ_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjn.h", "Xhwacha", "D,S,T", MATCH_FSGNJN_H, MASK_FSGNJN_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsgnjx.h", "Xhwacha", "D,S,T", MATCH_FSGNJX_H, MASK_FSGNJX_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.h", "Xhwacha", "D,S,T", MATCH_FADD_H | MASK_RM, MASK_FADD_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fadd.h", "Xhwacha", "D,S,T,m", MATCH_FADD_H, MASK_FADD_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.h", "Xhwacha", "D,S,T", MATCH_FSUB_H | MASK_RM, MASK_FSUB_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsub.h", "Xhwacha", "D,S,T,m", MATCH_FSUB_H, MASK_FSUB_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.h", "Xhwacha", "D,S,T", MATCH_FMUL_H | MASK_RM, MASK_FMUL_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmul.h", "Xhwacha", "D,S,T,m", MATCH_FMUL_H, MASK_FMUL_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.h", "Xhwacha", "D,S,T", MATCH_FDIV_H | MASK_RM, MASK_FDIV_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fdiv.h", "Xhwacha", "D,S,T,m", MATCH_FDIV_H, MASK_FDIV_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fsqrt.h", "Xhwacha", "D,S", MATCH_FSQRT_H | MASK_RM, MASK_FSQRT_H | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fsqrt.h", "Xhwacha", "D,S,m", MATCH_FSQRT_H, MASK_FSQRT_H, match_opcode, WR_fd|RD_fs1 },
+{"fmin.h", "Xhwacha", "D,S,T", MATCH_FMIN_H, MASK_FMIN_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmax.h", "Xhwacha", "D,S,T", MATCH_FMAX_H, MASK_FMAX_H, match_opcode, WR_fd|RD_fs1|RD_fs2 },
+{"fmadd.h", "Xhwacha", "D,S,T,R", MATCH_FMADD_H | MASK_RM, MASK_FMADD_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmadd.h", "Xhwacha", "D,S,T,R,m", MATCH_FMADD_H, MASK_FMADD_H, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.h", "Xhwacha", "D,S,T,R", MATCH_FNMADD_H | MASK_RM, MASK_FNMADD_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmadd.h", "Xhwacha", "D,S,T,R,m", MATCH_FNMADD_H, MASK_FNMADD_H, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.h", "Xhwacha", "D,S,T,R", MATCH_FMSUB_H | MASK_RM, MASK_FMSUB_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fmsub.h", "Xhwacha", "D,S,T,R,m", MATCH_FMSUB_H, MASK_FMSUB_H, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.h", "Xhwacha", "D,S,T,R", MATCH_FNMSUB_H | MASK_RM, MASK_FNMSUB_H | MASK_RM, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fnmsub.h", "Xhwacha", "D,S,T,R,m", MATCH_FNMSUB_H, MASK_FNMSUB_H, match_opcode, WR_fd|RD_fs1|RD_fs2|RD_fs3 },
+{"fcvt.s.h", "Xhwacha", "D,S", MATCH_FCVT_S_H, MASK_FCVT_S_H | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.h.s", "Xhwacha", "D,S", MATCH_FCVT_H_S | MASK_RM, MASK_FCVT_H_S | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.h.s", "Xhwacha", "D,S,m", MATCH_FCVT_H_S, MASK_FCVT_H_S, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.d.h", "Xhwacha", "D,S", MATCH_FCVT_D_H, MASK_FCVT_D_H | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.h.d", "Xhwacha", "D,S", MATCH_FCVT_H_D | MASK_RM, MASK_FCVT_H_D | MASK_RM, match_opcode, WR_fd|RD_fs1 },
+{"fcvt.h.d", "Xhwacha", "D,S,m", MATCH_FCVT_H_D, MASK_FCVT_H_D, match_opcode, WR_fd|RD_fs1 },
+{"feq.h", "Xhwacha", "d,S,T", MATCH_FEQ_H, MASK_FEQ_H, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"flt.h", "Xhwacha", "d,S,T", MATCH_FLT_H, MASK_FLT_H, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fle.h", "Xhwacha", "d,S,T", MATCH_FLE_H, MASK_FLE_H, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fgt.h", "Xhwacha", "d,T,S", MATCH_FLT_H, MASK_FLT_H, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fge.h", "Xhwacha", "d,T,S", MATCH_FLE_H, MASK_FLE_H, match_opcode, WR_xd|RD_fs1|RD_fs2 },
+{"fmv.x.h", "Xhwacha", "d,S", MATCH_FMV_X_H, MASK_FMV_X_H, match_opcode, WR_xd|RD_fs1 },
+{"fmv.h.x", "Xhwacha", "D,s", MATCH_FMV_H_X, MASK_FMV_H_X, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.w.h", "Xhwacha", "d,S", MATCH_FCVT_W_H | MASK_RM, MASK_FCVT_W_H | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.w.h", "Xhwacha", "d,S,m", MATCH_FCVT_W_H, MASK_FCVT_W_H, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.h", "Xhwacha", "d,S", MATCH_FCVT_WU_H | MASK_RM, MASK_FCVT_WU_H | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.wu.h", "Xhwacha", "d,S,m", MATCH_FCVT_WU_H, MASK_FCVT_WU_H, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.h.w", "Xhwacha", "D,s", MATCH_FCVT_H_W, MASK_FCVT_H_W | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.h.wu", "Xhwacha", "D,s", MATCH_FCVT_H_WU, MASK_FCVT_H_WU | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.l.h", "Xhwacha", "d,S", MATCH_FCVT_L_H | MASK_RM, MASK_FCVT_L_H | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.l.h", "Xhwacha", "d,S,m", MATCH_FCVT_L_H, MASK_FCVT_L_H, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.h", "Xhwacha", "d,S", MATCH_FCVT_LU_H | MASK_RM, MASK_FCVT_LU_H | MASK_RM, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.lu.h", "Xhwacha", "d,S,m", MATCH_FCVT_LU_H, MASK_FCVT_LU_H, match_opcode, WR_xd|RD_fs1 },
+{"fcvt.h.l", "Xhwacha", "D,s", MATCH_FCVT_H_L | MASK_RM, MASK_FCVT_H_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.h.l", "Xhwacha", "D,s,m", MATCH_FCVT_H_L, MASK_FCVT_H_L, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.h.lu", "Xhwacha", "D,s", MATCH_FCVT_H_LU | MASK_RM, MASK_FCVT_H_L | MASK_RM, match_opcode, WR_fd|RD_xs1 },
+{"fcvt.h.lu", "Xhwacha", "D,s,m", MATCH_FCVT_H_LU, MASK_FCVT_H_LU, match_opcode, WR_fd|RD_xs1 },
+
+/* Rocket Custom Coprocessor extension */
+{"custom0", "Xcustom", "d,s,t,^j", MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2, match_opcode, 0},
+{"custom0", "Xcustom", "d,s,^t,^j", MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1, match_opcode, 0},
+{"custom0", "Xcustom", "d,^s,^t,^j", MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD, match_opcode, 0},
+{"custom0", "Xcustom", "^d,s,t,^j", MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2, match_opcode, 0},
+{"custom0", "Xcustom", "^d,s,^t,^j", MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1, match_opcode, 0},
+{"custom0", "Xcustom", "^d,^s,^t,^j", MATCH_CUSTOM0, MASK_CUSTOM0, match_opcode, 0},
+{"custom1", "Xcustom", "d,s,t,^j", MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2, match_opcode, 0},
+{"custom1", "Xcustom", "d,s,^t,^j", MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1, match_opcode, 0},
+{"custom1", "Xcustom", "d,^s,^t,^j", MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD, match_opcode, 0},
+{"custom1", "Xcustom", "^d,s,t,^j", MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2, match_opcode, 0},
+{"custom1", "Xcustom", "^d,s,^t,^j", MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1, match_opcode, 0},
+{"custom1", "Xcustom", "^d,^s,^t,^j", MATCH_CUSTOM1, MASK_CUSTOM1, match_opcode, 0},
+{"custom2", "Xcustom", "d,s,t,^j", MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2, match_opcode, 0},
+{"custom2", "Xcustom", "d,s,^t,^j", MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1, match_opcode, 0},
+{"custom2", "Xcustom", "d,^s,^t,^j", MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD, match_opcode, 0},
+{"custom2", "Xcustom", "^d,s,t,^j", MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2, match_opcode, 0},
+{"custom2", "Xcustom", "^d,s,^t,^j", MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1, match_opcode, 0},
+{"custom2", "Xcustom", "^d,^s,^t,^j", MATCH_CUSTOM2, MASK_CUSTOM2, match_opcode, 0},
+{"custom3", "Xcustom", "d,s,t,^j", MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2, match_opcode, 0},
+{"custom3", "Xcustom", "d,s,^t,^j", MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1, match_opcode, 0},
+{"custom3", "Xcustom", "d,^s,^t,^j", MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD, match_opcode, 0},
+{"custom3", "Xcustom", "^d,s,t,^j", MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2, match_opcode, 0},
+{"custom3", "Xcustom", "^d,s,^t,^j", MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1, match_opcode, 0},
+{"custom3", "Xcustom", "^d,^s,^t,^j", MATCH_CUSTOM3, MASK_CUSTOM3, match_opcode, 0},
+
+/* Xhwacha extension */
+{"stop", "Xhwacha", "", MATCH_STOP, MASK_STOP, match_opcode, 0},
+{"utidx", "Xhwacha", "d", MATCH_UTIDX, MASK_UTIDX, match_opcode, WR_xd},
+{"movz", "Xhwacha", "d,s,t", MATCH_MOVZ, MASK_MOVZ, match_opcode, WR_xd|RD_xs1|RD_xs2},
+{"movn", "Xhwacha", "d,s,t", MATCH_MOVN, MASK_MOVN, match_opcode, WR_xd|RD_xs1|RD_xs2},
+{"fmovz", "Xhwacha", "D,s,T", MATCH_FMOVZ, MASK_FMOVZ, match_opcode, WR_fd|RD_xs1|RD_fs2},
+{"fmovn", "Xhwacha", "D,s,T", MATCH_FMOVN, MASK_FMOVN, match_opcode, WR_fd|RD_xs1|RD_fs2},
+
+/* unit stride */
+/* xloads */
+{"vld", "Xhwacha", "#d,s", MATCH_VLD, MASK_VLD, match_opcode, 0},
+{"vlw", "Xhwacha", "#d,s", MATCH_VLW, MASK_VLW, match_opcode, 0},
+{"vlwu", "Xhwacha", "#d,s", MATCH_VLWU, MASK_VLWU, match_opcode, 0},
+{"vlh", "Xhwacha", "#d,s", MATCH_VLH, MASK_VLH, match_opcode, 0},
+{"vlhu", "Xhwacha", "#d,s", MATCH_VLHU, MASK_VLHU, match_opcode, 0},
+{"vlb", "Xhwacha", "#d,s", MATCH_VLB, MASK_VLB, match_opcode, 0},
+{"vlbu", "Xhwacha", "#d,s", MATCH_VLBU, MASK_VLBU, match_opcode, 0},
+/* floads */
+{"vfld", "Xhwacha", "#D,s", MATCH_VFLD, MASK_VFLD, match_opcode, 0},
+{"vflw", "Xhwacha", "#D,s", MATCH_VFLW, MASK_VFLW, match_opcode, 0},
+
+/* stride */
+/* xloads */
+{"vlstd", "Xhwacha", "#d,s,t", MATCH_VLSTD, MASK_VLSTD, match_opcode, 0},
+{"vlstw", "Xhwacha", "#d,s,t", MATCH_VLSTW, MASK_VLSTW, match_opcode, 0},
+{"vlstwu", "Xhwacha", "#d,s,t", MATCH_VLSTWU, MASK_VLSTWU, match_opcode, 0},
+{"vlsth", "Xhwacha", "#d,s,t", MATCH_VLSTH, MASK_VLSTH, match_opcode, 0},
+{"vlsthu", "Xhwacha", "#d,s,t", MATCH_VLSTHU, MASK_VLSTHU, match_opcode, 0},
+{"vlstb", "Xhwacha", "#d,s,t", MATCH_VLSTB, MASK_VLSTB, match_opcode, 0},
+{"vlstbu", "Xhwacha", "#d,s,t", MATCH_VLSTBU, MASK_VLSTBU, match_opcode, 0},
+/* floads */
+{"vflstd", "Xhwacha", "#D,s,t", MATCH_VFLSTD, MASK_VFLSTD, match_opcode, 0},
+{"vflstw", "Xhwacha", "#D,s,t", MATCH_VFLSTW, MASK_VFLSTW, match_opcode, 0},
+
+/* segment */
+/* xloads */
+{"vlsegd", "Xhwacha", "#d,s,#n", MATCH_VLSEGD, MASK_VLSEGD, match_opcode, 0},
+{"vlsegw", "Xhwacha", "#d,s,#n", MATCH_VLSEGW, MASK_VLSEGW, match_opcode, 0},
+{"vlsegwu", "Xhwacha", "#d,s,#n", MATCH_VLSEGWU, MASK_VLSEGWU, match_opcode, 0},
+{"vlsegh", "Xhwacha", "#d,s,#n", MATCH_VLSEGH, MASK_VLSEGH, match_opcode, 0},
+{"vlseghu", "Xhwacha", "#d,s,#n", MATCH_VLSEGHU, MASK_VLSEGHU, match_opcode, 0},
+{"vlsegb", "Xhwacha", "#d,s,#n", MATCH_VLSEGB, MASK_VLSEGB, match_opcode, 0},
+{"vlsegbu", "Xhwacha", "#d,s,#n", MATCH_VLSEGBU, MASK_VLSEGBU, match_opcode, 0},
+/* floads */
+{"vflsegd", "Xhwacha", "#D,s,#n", MATCH_VFLSEGD, MASK_VFLSEGD, match_opcode, 0},
+{"vflsegw", "Xhwacha", "#D,s,#n", MATCH_VFLSEGW, MASK_VFLSEGW, match_opcode, 0},
+
+/* stride segment */
+/* xloads */
+{"vlsegstd", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTD, MASK_VLSEGSTD, match_opcode, 0},
+{"vlsegstw", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTW, MASK_VLSEGSTW, match_opcode, 0},
+{"vlsegstwu", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTWU, MASK_VLSEGSTWU, match_opcode, 0},
+{"vlsegsth", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTH, MASK_VLSEGSTH, match_opcode, 0},
+{"vlsegsthu", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTHU, MASK_VLSEGSTHU, match_opcode, 0},
+{"vlsegstb", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTB, MASK_VLSEGSTB, match_opcode, 0},
+{"vlsegstbu", "Xhwacha", "#d,s,t,#n", MATCH_VLSEGSTBU, MASK_VLSEGSTBU, match_opcode, 0},
+/* floads */
+{"vflsegstd", "Xhwacha", "#D,s,t,#n", MATCH_VFLSEGSTD, MASK_VFLSEGSTD, match_opcode, 0},
+{"vflsegstw", "Xhwacha", "#D,s,t,#n", MATCH_VFLSEGSTW, MASK_VFLSEGSTW, match_opcode, 0},
+
+/* unit stride */
+/* xstores */
+{"vsd", "Xhwacha", "#d,s", MATCH_VSD, MASK_VSD, match_opcode, 0},
+{"vsw", "Xhwacha", "#d,s", MATCH_VSW, MASK_VSW, match_opcode, 0},
+{"vsh", "Xhwacha", "#d,s", MATCH_VSH, MASK_VSH, match_opcode, 0},
+{"vsb", "Xhwacha", "#d,s", MATCH_VSB, MASK_VSB, match_opcode, 0},
+/* fstores */
+{"vfsd", "Xhwacha", "#D,s", MATCH_VFSD, MASK_VFSD, match_opcode, 0},
+{"vfsw", "Xhwacha", "#D,s", MATCH_VFSW, MASK_VFSW, match_opcode, 0},
+
+/* stride */
+/* xstores */
+{"vsstd", "Xhwacha", "#d,s,t", MATCH_VSSTD, MASK_VSSTD, match_opcode, 0},
+{"vsstw", "Xhwacha", "#d,s,t", MATCH_VSSTW, MASK_VSSTW, match_opcode, 0},
+{"vssth", "Xhwacha", "#d,s,t", MATCH_VSSTH, MASK_VSSTH, match_opcode, 0},
+{"vsstb", "Xhwacha", "#d,s,t", MATCH_VSSTB, MASK_VSSTB, match_opcode, 0},
+/* fstores */
+{"vfsstd", "Xhwacha", "#D,s,t", MATCH_VFSSTD, MASK_VFSSTD, match_opcode, 0},
+{"vfsstw", "Xhwacha", "#D,s,t", MATCH_VFSSTW, MASK_VFSSTW, match_opcode, 0},
+
+/* segment */
+/* xstores */
+{"vssegd", "Xhwacha", "#d,s,#n", MATCH_VSSEGD, MASK_VSSEGD, match_opcode, 0},
+{"vssegw", "Xhwacha", "#d,s,#n", MATCH_VSSEGW, MASK_VSSEGW, match_opcode, 0},
+{"vssegh", "Xhwacha", "#d,s,#n", MATCH_VSSEGH, MASK_VSSEGH, match_opcode, 0},
+{"vssegb", "Xhwacha", "#d,s,#n", MATCH_VSSEGB, MASK_VSSEGB, match_opcode, 0},
+/* fstores */
+{"vfssegd", "Xhwacha", "#D,s,#n", MATCH_VFSSEGD, MASK_VFSSEGD, match_opcode, 0},
+{"vfssegw", "Xhwacha", "#D,s,#n", MATCH_VFSSEGW, MASK_VFSSEGW, match_opcode, 0},
+
+/* stride segment */
+/* xsegstores */
+{"vssegstd", "Xhwacha", "#d,s,t,#n", MATCH_VSSEGSTD, MASK_VSSEGSTD, match_opcode, 0},
+{"vssegstw", "Xhwacha", "#d,s,t,#n", MATCH_VSSEGSTW, MASK_VSSEGSTW, match_opcode, 0},
+{"vssegsth", "Xhwacha", "#d,s,t,#n", MATCH_VSSEGSTH, MASK_VSSEGSTH, match_opcode, 0},
+{"vssegstb", "Xhwacha", "#d,s,t,#n", MATCH_VSSEGSTB, MASK_VSSEGSTB, match_opcode, 0},
+/* fsegstores */
+{"vfssegstd", "Xhwacha", "#D,s,t,#n", MATCH_VFSSEGSTD, MASK_VFSSEGSTD, match_opcode, 0},
+{"vfssegstw", "Xhwacha", "#D,s,t,#n", MATCH_VFSSEGSTW, MASK_VFSSEGSTW, match_opcode, 0},
+
+{"vsetcfg", "Xhwacha", "s", MATCH_VSETCFG, MASK_VSETCFG | MASK_IMM, match_opcode, 0},
+{"vsetcfg", "Xhwacha", "#g,#f", MATCH_VSETCFG, MASK_VSETCFG | MASK_RS1, match_opcode, 0},
+{"vsetcfg", "Xhwacha", "s,#g,#f", MATCH_VSETCFG, MASK_VSETCFG, match_opcode, 0},
+{"vsetucfg", "Xhwacha", "d,u", MATCH_LUI, MASK_LUI, match_opcode, INSN_ALIAS | WR_xd},
+{"vsetvl", "Xhwacha", "d,s", MATCH_VSETVL, MASK_VSETVL, match_opcode, 0},
+{"vgetcfg", "Xhwacha", "d", MATCH_VGETCFG, MASK_VGETCFG, match_opcode, 0},
+{"vgetvl", "Xhwacha", "d", MATCH_VGETVL, MASK_VGETVL, match_opcode, 0},
+
+{"vmvv", "Xhwacha", "#d,#s", MATCH_VMVV, MASK_VMVV, match_opcode, 0},
+{"vmsv", "Xhwacha", "#d,s", MATCH_VMSV, MASK_VMSV, match_opcode, 0},
+{"vfmvv", "Xhwacha", "#D,#S", MATCH_VFMVV, MASK_VFMVV, match_opcode, 0},
+{"vfmsv.d", "Xhwacha", "#D,s", MATCH_VFMSV_D, MASK_VFMSV_D, match_opcode, 0},
+{"vfmsv.s", "Xhwacha", "#D,s", MATCH_VFMSV_S, MASK_VFMSV_S, match_opcode, 0},
+
+{"vf", "Xhwacha", "q(s)", MATCH_VF, MASK_VF, match_opcode, 0},
+{"vf", "Xhwacha", "A,s", 0, (int) M_VF, match_never, INSN_MACRO },
+
+{"vxcptcause", "Xhwacha", "d", MATCH_VXCPTCAUSE, MASK_VXCPTCAUSE, match_opcode, 0},
+{"vxcptaux", "Xhwacha", "d", MATCH_VXCPTAUX, MASK_VXCPTAUX, match_opcode, 0},
+
+{"vxcptsave", "Xhwacha", "s", MATCH_VXCPTSAVE, MASK_VXCPTSAVE, match_opcode, 0},
+{"vxcptrestore", "Xhwacha", "s", MATCH_VXCPTRESTORE, MASK_VXCPTRESTORE, match_opcode, 0},
+{"vxcptkill", "Xhwacha", "", MATCH_VXCPTKILL, MASK_VXCPTKILL, match_opcode, 0},
+
+{"vxcptevac", "Xhwacha", "s", MATCH_VXCPTEVAC, MASK_VXCPTEVAC, match_opcode, 0},
+{"vxcpthold", "Xhwacha", "", MATCH_VXCPTHOLD, MASK_VXCPTHOLD, match_opcode, 0},
+{"venqcmd", "Xhwacha", "s,t", MATCH_VENQCMD, MASK_VENQCMD, match_opcode, 0},
+{"venqimm1", "Xhwacha", "s,t", MATCH_VENQIMM1, MASK_VENQIMM1, match_opcode, 0},
+{"venqimm2", "Xhwacha", "s,t", MATCH_VENQIMM2, MASK_VENQIMM2, match_opcode, 0},
+{"venqcnt", "Xhwacha", "s,t", MATCH_VENQCNT, MASK_VENQCNT, match_opcode, 0},
+};
+
+#define RISCV_NUM_OPCODES \
+ ((sizeof riscv_builtin_opcodes) / (sizeof (riscv_builtin_opcodes[0])))
+const int bfd_riscv_num_builtin_opcodes = RISCV_NUM_OPCODES;
+
+/* const removed from the following to allow for dynamic extensions to the
+ * built-in instruction set. */
+struct riscv_opcode *riscv_opcodes =
+ (struct riscv_opcode *) riscv_builtin_opcodes;
+int bfd_riscv_num_opcodes = RISCV_NUM_OPCODES;
+#undef RISCV_NUM_OPCODES