| Created from https://github.com/riscv/riscv-gnu-toolchain, |
| commit ddce5d17f14831f4957e57c415aca77817c2a82c |
| |
| diff -urN original-binutils/bfd/archures.c binutils/bfd/archures.c |
| --- original-binutils/bfd/archures.c 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/bfd/archures.c 2015-03-07 09:55:02.355135671 +0100 |
| @@ -597,6 +597,7 @@ |
| extern const bfd_arch_info_type bfd_plugin_arch; |
| extern const bfd_arch_info_type bfd_powerpc_archs[]; |
| #define bfd_powerpc_arch bfd_powerpc_archs[0] |
| +extern const bfd_arch_info_type bfd_riscv_arch; |
| extern const bfd_arch_info_type bfd_rs6000_arch; |
| extern const bfd_arch_info_type bfd_rl78_arch; |
| extern const bfd_arch_info_type bfd_rx_arch; |
| @@ -683,6 +684,7 @@ |
| &bfd_or1k_arch, |
| &bfd_pdp11_arch, |
| &bfd_powerpc_arch, |
| + &bfd_riscv_arch, |
| &bfd_rs6000_arch, |
| &bfd_rl78_arch, |
| &bfd_rx_arch, |
| diff -urN original-binutils/bfd/bfd-in2.h binutils/bfd/bfd-in2.h |
| --- original-binutils/bfd/bfd-in2.h 2014-11-04 10:54:41.000000000 +0100 |
| +++ binutils-2.25/bfd/bfd-in2.h 2015-03-07 09:55:02.359135671 +0100 |
| @@ -2043,6 +2043,9 @@ |
| #define bfd_mach_ppc_e6500 5007 |
| #define bfd_mach_ppc_titan 83 |
| #define bfd_mach_ppc_vle 84 |
| + 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 |
| @@ -5531,6 +5534,41 @@ |
| 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_ADD8, |
| + BFD_RELOC_RISCV_ADD16, |
| + BFD_RELOC_RISCV_ADD32, |
| + BFD_RELOC_RISCV_ADD64, |
| + BFD_RELOC_RISCV_SUB8, |
| + BFD_RELOC_RISCV_SUB16, |
| + BFD_RELOC_RISCV_SUB32, |
| + BFD_RELOC_RISCV_SUB64, |
| + BFD_RELOC_RISCV_GOT_HI20, |
| + BFD_RELOC_RISCV_TLS_GOT_HI20, |
| + BFD_RELOC_RISCV_TLS_GD_HI20, |
| + BFD_RELOC_RISCV_JMP, |
| + BFD_RELOC_RISCV_TLS_DTPMOD32, |
| + BFD_RELOC_RISCV_TLS_DTPREL32, |
| + BFD_RELOC_RISCV_TLS_DTPMOD64, |
| + BFD_RELOC_RISCV_TLS_DTPREL64, |
| + BFD_RELOC_RISCV_TLS_TPREL32, |
| + BFD_RELOC_RISCV_TLS_TPREL64, |
| + BFD_RELOC_RISCV_ALIGN, |
| + |
| /* 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 -urN original-binutils/bfd/config.bfd binutils/bfd/config.bfd |
| --- original-binutils/bfd/config.bfd 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/bfd/config.bfd 2015-03-07 09:55:02.359135671 +0100 |
| @@ -119,6 +119,7 @@ |
| pdp11*) targ_archs=bfd_pdp11_arch ;; |
| pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; |
| powerpc*) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; |
| +riscv*) targ_archs=bfd_riscv_arch ;; |
| rs6000) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; |
| s390*) targ_archs=bfd_s390_arch ;; |
| sh*) targ_archs=bfd_sh_arch ;; |
| @@ -1319,6 +1320,14 @@ |
| targ_defvec=rl78_elf32_vec |
| ;; |
| |
| +#ifdef BFD64 |
| + riscv*-*-*) |
| + targ_defvec=riscv_elf64_vec |
| + targ_selvecs="riscv_elf32_vec riscv_elf64_vec" |
| + want64=true |
| + ;; |
| +#endif |
| + |
| rx-*-elf) |
| targ_defvec=rx_elf32_le_vec |
| targ_selvecs="rx_elf32_be_vec rx_elf32_le_vec rx_elf32_be_ns_vec" |
| diff -urN original-binutils/bfd/configure binutils/bfd/configure |
| --- original-binutils/bfd/configure 2014-12-23 15:22:04.000000000 +0100 |
| +++ binutils-2.25/bfd/configure 2015-03-07 09:55:02.367135671 +0100 |
| @@ -15506,6 +15506,8 @@ |
| powerpc_pei_vec) tb="$tb pei-ppc.lo peigen.lo cofflink.lo" ;; |
| powerpc_pei_le_vec) tb="$tb pei-ppc.lo peigen.lo cofflink.lo" ;; |
| powerpc_xcoff_vec) tb="$tb coff-rs6000.lo xcofflink.lo" ;; |
| + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf" ;; |
| + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf"; target_size=64 ;; |
| rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;; |
| rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; |
| rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; |
| diff -urN original-binutils/bfd/configure.ac binutils/bfd/configure.ac |
| --- original-binutils/bfd/configure.ac 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/bfd/configure.ac 2015-03-07 09:55:02.367135671 +0100 |
| @@ -907,6 +907,8 @@ |
| powerpc_pei_vec) tb="$tb pei-ppc.lo peigen.lo cofflink.lo" ;; |
| powerpc_pei_le_vec) tb="$tb pei-ppc.lo peigen.lo cofflink.lo" ;; |
| powerpc_xcoff_vec) tb="$tb coff-rs6000.lo xcofflink.lo" ;; |
| + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf" ;; |
| + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf"; target_size=64 ;; |
| rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;; |
| rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; |
| rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo xcofflink.lo aix5ppc-core.lo"; target_size=64 ;; |
| diff -urN original-binutils/bfd/cpu-riscv.c binutils/bfd/cpu-riscv.c |
| --- original-binutils/bfd/cpu-riscv.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/bfd/cpu-riscv.c 2015-03-07 09:51:45.655139025 +0100 |
| @@ -0,0 +1,80 @@ |
| +/* BFD backend for RISC-V |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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 *riscv_compatible |
| + (const bfd_arch_info_type *, const bfd_arch_info_type *); |
| + |
| +/* The default routine tests bits_per_word, which is wrong on RISC-V, as |
| + RISC-V word size doesn't correlate with reloc size. */ |
| + |
| +static const bfd_arch_info_type * |
| +riscv_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_riscv_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, \ |
| + riscv_compatible, \ |
| + bfd_default_scan, \ |
| + bfd_arch_default_fill, \ |
| + 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 -urN original-binutils/bfd/elf-bfd.h binutils/bfd/elf-bfd.h |
| --- original-binutils/bfd/elf-bfd.h 2014-12-23 09:47:10.000000000 +0100 |
| +++ binutils-2.25/bfd/elf-bfd.h 2015-03-07 09:55:02.367135671 +0100 |
| @@ -433,6 +433,7 @@ |
| XGATE_ELF_DATA, |
| TILEGX_ELF_DATA, |
| TILEPRO_ELF_DATA, |
| + RISCV_ELF_DATA, |
| GENERIC_ELF_DATA |
| }; |
| |
| diff -urN original-binutils/bfd/elfnn-riscv.c binutils/bfd/elfnn-riscv.c |
| --- original-binutils/bfd/elfnn-riscv.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/bfd/elfnn-riscv.c 2015-03-07 09:51:45.655139025 +0100 |
| @@ -0,0 +1,2954 @@ |
| +/* RISC-V-specific support for NN-bit ELF. |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on TILE-Gx and MIPS targets. |
| + |
| + 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 RISC-V ELF targets. */ |
| + |
| +#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" |
| + |
| +#define ARCH_SIZE NN |
| + |
| +#define MINUS_ONE ((bfd_vma)0 - 1) |
| + |
| +#define RISCV_ELF_LOG_WORD_BYTES (ARCH_SIZE == 32 ? 2 : 3) |
| + |
| +#define RISCV_ELF_WORD_BYTES (1 << RISCV_ELF_LOG_WORD_BYTES) |
| + |
| +/* The name of the dynamic interpreter. This is put in the .interp |
| + section. */ |
| + |
| +#define ELF64_DYNAMIC_INTERPRETER "/lib/ld.so.1" |
| +#define ELF32_DYNAMIC_INTERPRETER "/lib32/ld.so.1" |
| + |
| +/* The RISC-V linker needs to keep track of the number of relocs that it |
| + decides to copy as dynamic relocs in check_relocs for each symbol. |
| + This is so that it can later discard them if they are found to be |
| + unnecessary. We store the information in a field extending the |
| + regular ELF linker hash table. */ |
| + |
| +struct riscv_elf_dyn_relocs |
| +{ |
| + struct riscv_elf_dyn_relocs *next; |
| + |
| + /* The input section of the reloc. */ |
| + asection *sec; |
| + |
| + /* Total number of relocs copied for the input section. */ |
| + bfd_size_type count; |
| + |
| + /* Number of pc-relative relocs copied for the input section. */ |
| + bfd_size_type pc_count; |
| +}; |
| + |
| +/* RISC-V ELF linker hash entry. */ |
| + |
| +struct riscv_elf_link_hash_entry |
| +{ |
| + struct elf_link_hash_entry elf; |
| + |
| + /* Track dynamic relocs copied for this symbol. */ |
| + struct riscv_elf_dyn_relocs *dyn_relocs; |
| + |
| +#define GOT_UNKNOWN 0 |
| +#define GOT_NORMAL 1 |
| +#define GOT_TLS_GD 2 |
| +#define GOT_TLS_IE 4 |
| +#define GOT_TLS_LE 8 |
| + char tls_type; |
| +}; |
| + |
| +#define riscv_elf_hash_entry(ent) \ |
| + ((struct riscv_elf_link_hash_entry *)(ent)) |
| + |
| +struct _bfd_riscv_elf_obj_tdata |
| +{ |
| + struct elf_obj_tdata root; |
| + |
| + /* tls_type for each local got entry. */ |
| + char *local_got_tls_type; |
| +}; |
| + |
| +#define _bfd_riscv_elf_tdata(abfd) \ |
| + ((struct _bfd_riscv_elf_obj_tdata *) (abfd)->tdata.any) |
| + |
| +#define _bfd_riscv_elf_local_got_tls_type(abfd) \ |
| + (_bfd_riscv_elf_tdata (abfd)->local_got_tls_type) |
| + |
| +#define _bfd_riscv_elf_tls_type(abfd, h, symndx) \ |
| + (*((h) != NULL ? &riscv_elf_hash_entry(h)->tls_type \ |
| + : &_bfd_riscv_elf_local_got_tls_type (abfd) [symndx])) |
| + |
| +#define is_riscv_elf(bfd) \ |
| + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ |
| + && elf_tdata (bfd) != NULL \ |
| + && elf_object_id (bfd) == RISCV_ELF_DATA) |
| + |
| +#include "elf/common.h" |
| +#include "elf/internal.h" |
| + |
| +struct riscv_elf_link_hash_table |
| +{ |
| + struct elf_link_hash_table elf; |
| + |
| + /* Short-cuts to get to dynamic linker sections. */ |
| + asection *sdynbss; |
| + asection *srelbss; |
| + asection *sdyntdata; |
| + |
| + /* Small local sym to section mapping cache. */ |
| + struct sym_cache sym_cache; |
| +}; |
| + |
| + |
| +/* Get the RISC-V ELF linker hash table from a link_info structure. */ |
| +#define riscv_elf_hash_table(p) \ |
| + (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ |
| + == RISCV_ELF_DATA ? ((struct riscv_elf_link_hash_table *) ((p)->hash)) : NULL) |
| + |
| +static void |
| +riscv_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, |
| + arelent *cache_ptr, |
| + Elf_Internal_Rela *dst) |
| +{ |
| + cache_ptr->howto = riscv_elf_rtype_to_howto (ELFNN_R_TYPE (dst->r_info)); |
| +} |
| + |
| +static void |
| +riscv_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) |
| +{ |
| + const struct elf_backend_data *bed; |
| + bfd_byte *loc; |
| + |
| + bed = get_elf_backend_data (abfd); |
| + loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); |
| + bed->s->swap_reloca_out (abfd, rel, loc); |
| +} |
| + |
| +/* PLT/GOT stuff */ |
| + |
| +#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 GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES |
| + |
| +#define GOTPLT_HEADER_SIZE (2 * GOT_ENTRY_SIZE) |
| + |
| +#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) |
| +{ |
| + return sec_addr (riscv_elf_hash_table (info)->elf.sgotplt) |
| + + GOTPLT_HEADER_SIZE + (plt_index * GOT_ENTRY_SIZE); |
| +} |
| + |
| +#if ARCH_SIZE == 32 |
| +# define MATCH_LREG MATCH_LW |
| +#else |
| +# define MATCH_LREG MATCH_LD |
| +#endif |
| + |
| +/* The format of the first PLT entry. */ |
| + |
| +static void |
| +riscv_make_plt0_entry(bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry) |
| +{ |
| + /* auipc t2, %hi(.got.plt) |
| + sub t1, t1, t0 # shifted .got.plt offset + hdr size + 12 |
| + l[w|d] t3, %lo(.got.plt)(t2) # _dl_runtime_resolve |
| + addi t1, t1, -(hdr size + 12) # shifted .got.plt offset |
| + addi t0, t2, %lo(.got.plt) # &.got.plt |
| + srli t1, t1, log2(16/PTRSIZE) # .got.plt offset |
| + l[w|d] t0, PTRSIZE(t0) # link map |
| + jr t3 */ |
| + |
| + entry[0] = RISCV_UTYPE (AUIPC, X_T2, RISCV_PCREL_HIGH_PART (gotplt_addr, addr)); |
| + entry[1] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T0); |
| + entry[2] = RISCV_ITYPE (LREG, X_T3, X_T2, RISCV_PCREL_LOW_PART (gotplt_addr, addr)); |
| + entry[3] = RISCV_ITYPE (ADDI, X_T1, X_T1, -(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_T1, 4 - RISCV_ELF_LOG_WORD_BYTES); |
| + entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES); |
| + entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0); |
| +} |
| + |
| +/* The format of subsequent PLT entries. */ |
| + |
| +static void |
| +riscv_make_plt_entry(bfd_vma got_address, bfd_vma addr, uint32_t *entry) |
| +{ |
| + /* auipc t1, %hi(.got.plt entry) |
| + l[w|d] t0, %lo(.got.plt entry)(t1) |
| + jalr t1, t0 |
| + nop */ |
| + |
| + entry[0] = RISCV_UTYPE (AUIPC, X_T1, RISCV_PCREL_HIGH_PART (got_address, addr)); |
| + entry[1] = RISCV_ITYPE (LREG, X_T0, X_T1, RISCV_PCREL_LOW_PART(got_address, addr)); |
| + entry[2] = RISCV_ITYPE (JALR, X_T1, X_T0, 0); |
| + entry[3] = RISCV_NOP; |
| +} |
| + |
| +/* Create an entry in an RISC-V ELF linker hash table. */ |
| + |
| +static struct bfd_hash_entry * |
| +link_hash_newfunc (struct bfd_hash_entry *entry, |
| + struct bfd_hash_table *table, const char *string) |
| +{ |
| + /* Allocate the structure if it has not already been allocated by a |
| + subclass. */ |
| + if (entry == NULL) |
| + { |
| + entry = |
| + bfd_hash_allocate (table, |
| + sizeof (struct riscv_elf_link_hash_entry)); |
| + if (entry == NULL) |
| + return entry; |
| + } |
| + |
| + /* Call the allocation method of the superclass. */ |
| + entry = _bfd_elf_link_hash_newfunc (entry, table, string); |
| + if (entry != NULL) |
| + { |
| + struct riscv_elf_link_hash_entry *eh; |
| + |
| + eh = (struct riscv_elf_link_hash_entry *) entry; |
| + eh->dyn_relocs = NULL; |
| + eh->tls_type = GOT_UNKNOWN; |
| + } |
| + |
| + return entry; |
| +} |
| + |
| +/* Create a RISC-V ELF linker hash table. */ |
| + |
| +static struct bfd_link_hash_table * |
| +riscv_elf_link_hash_table_create (bfd *abfd) |
| +{ |
| + struct riscv_elf_link_hash_table *ret; |
| + bfd_size_type amt = sizeof (struct riscv_elf_link_hash_table); |
| + |
| + ret = (struct riscv_elf_link_hash_table *) bfd_zmalloc (amt); |
| + if (ret == NULL) |
| + return NULL; |
| + |
| + if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, |
| + sizeof (struct riscv_elf_link_hash_entry), |
| + RISCV_ELF_DATA)) |
| + { |
| + free (ret); |
| + return NULL; |
| + } |
| + |
| + return &ret->elf.root; |
| +} |
| + |
| +/* Create the .got section. */ |
| + |
| +static bfd_boolean |
| +riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) |
| +{ |
| + flagword flags; |
| + asection *s, *s_got; |
| + struct elf_link_hash_entry *h; |
| + const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
| + struct elf_link_hash_table *htab = elf_hash_table (info); |
| + |
| + /* This function may be called more than once. */ |
| + s = bfd_get_linker_section (abfd, ".got"); |
| + if (s != NULL) |
| + return TRUE; |
| + |
| + flags = bed->dynamic_sec_flags; |
| + |
| + s = bfd_make_section_anyway_with_flags (abfd, |
| + (bed->rela_plts_and_copies_p |
| + ? ".rela.got" : ".rel.got"), |
| + (bed->dynamic_sec_flags |
| + | SEC_READONLY)); |
| + if (s == NULL |
| + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
| + return FALSE; |
| + htab->srelgot = s; |
| + |
| + s = s_got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); |
| + if (s == NULL |
| + || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) |
| + return FALSE; |
| + htab->sgot = s; |
| + |
| + /* The first bit of the global offset table is the header. */ |
| + s->size += bed->got_header_size; |
| + |
| + if (bed->want_got_plt) |
| + { |
| + s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); |
| + if (s == NULL |
| + || !bfd_set_section_alignment (abfd, s, |
| + bed->s->log_file_align)) |
| + return FALSE; |
| + htab->sgotplt = s; |
| + |
| + /* Reserve room for the header. */ |
| + s->size += GOTPLT_HEADER_SIZE; |
| + } |
| + |
| + if (bed->want_got_sym) |
| + { |
| + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got |
| + section. 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. */ |
| + h = _bfd_elf_define_linkage_sym (abfd, info, s_got, |
| + "_GLOBAL_OFFSET_TABLE_"); |
| + elf_hash_table (info)->hgot = h; |
| + if (h == NULL) |
| + return FALSE; |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and |
| + .rela.bss sections in DYNOBJ, and set up shortcuts to them in our |
| + hash table. */ |
| + |
| +static bfd_boolean |
| +riscv_elf_create_dynamic_sections (bfd *dynobj, |
| + struct bfd_link_info *info) |
| +{ |
| + struct riscv_elf_link_hash_table *htab; |
| + |
| + htab = riscv_elf_hash_table (info); |
| + BFD_ASSERT (htab != NULL); |
| + |
| + if (!riscv_elf_create_got_section (dynobj, info)) |
| + return FALSE; |
| + |
| + if (!_bfd_elf_create_dynamic_sections (dynobj, info)) |
| + return FALSE; |
| + |
| + htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); |
| + if (!info->shared) |
| + { |
| + htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); |
| + htab->sdyntdata = |
| + bfd_make_section_anyway_with_flags (dynobj, ".tdata.dyn", |
| + SEC_ALLOC | SEC_THREAD_LOCAL); |
| + } |
| + |
| + if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss |
| + || (!info->shared && (!htab->srelbss || !htab->sdyntdata))) |
| + abort (); |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Copy the extra info we tack onto an elf_link_hash_entry. */ |
| + |
| +static void |
| +riscv_elf_copy_indirect_symbol (struct bfd_link_info *info, |
| + struct elf_link_hash_entry *dir, |
| + struct elf_link_hash_entry *ind) |
| +{ |
| + struct riscv_elf_link_hash_entry *edir, *eind; |
| + |
| + edir = (struct riscv_elf_link_hash_entry *) dir; |
| + eind = (struct riscv_elf_link_hash_entry *) ind; |
| + |
| + if (eind->dyn_relocs != NULL) |
| + { |
| + if (edir->dyn_relocs != NULL) |
| + { |
| + struct riscv_elf_dyn_relocs **pp; |
| + struct riscv_elf_dyn_relocs *p; |
| + |
| + /* Add reloc counts against the indirect sym to the direct sym |
| + list. Merge any entries against the same section. */ |
| + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) |
| + { |
| + struct riscv_elf_dyn_relocs *q; |
| + |
| + for (q = edir->dyn_relocs; q != NULL; q = q->next) |
| + if (q->sec == p->sec) |
| + { |
| + q->pc_count += p->pc_count; |
| + q->count += p->count; |
| + *pp = p->next; |
| + break; |
| + } |
| + if (q == NULL) |
| + pp = &p->next; |
| + } |
| + *pp = edir->dyn_relocs; |
| + } |
| + |
| + edir->dyn_relocs = eind->dyn_relocs; |
| + eind->dyn_relocs = NULL; |
| + } |
| + |
| + if (ind->root.type == bfd_link_hash_indirect |
| + && dir->got.refcount <= 0) |
| + { |
| + edir->tls_type = eind->tls_type; |
| + eind->tls_type = GOT_UNKNOWN; |
| + } |
| + _bfd_elf_link_hash_copy_indirect (info, dir, ind); |
| +} |
| + |
| +static bfd_boolean |
| +riscv_elf_record_tls_type (bfd *abfd, struct elf_link_hash_entry *h, |
| + unsigned long symndx, char tls_type) |
| +{ |
| + char *new_tls_type = &_bfd_riscv_elf_tls_type (abfd, h, symndx); |
| + *new_tls_type |= tls_type; |
| + if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL)) |
| + { |
| + (*_bfd_error_handler) |
| + (_("%B: `%s' accessed both as normal and thread local symbol"), |
| + abfd, h ? h->root.root.string : "<local>"); |
| + return FALSE; |
| + } |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, |
| + struct elf_link_hash_entry *h, long symndx) |
| +{ |
| + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); |
| + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| + |
| + if (htab->elf.sgot == NULL) |
| + { |
| + if (!riscv_elf_create_got_section (htab->elf.dynobj, info)) |
| + return FALSE; |
| + } |
| + |
| + if (h != NULL) |
| + { |
| + h->got.refcount += 1; |
| + return TRUE; |
| + } |
| + |
| + /* This is a global offset table entry for a local symbol. */ |
| + if (elf_local_got_refcounts (abfd) == NULL) |
| + { |
| + bfd_size_type size = symtab_hdr->sh_info * (sizeof (bfd_vma) + 1); |
| + if (!(elf_local_got_refcounts (abfd) = bfd_zalloc (abfd, size))) |
| + return FALSE; |
| + _bfd_riscv_elf_local_got_tls_type (abfd) |
| + = (char *) (elf_local_got_refcounts (abfd) + symtab_hdr->sh_info); |
| + } |
| + elf_local_got_refcounts (abfd) [symndx] += 1; |
| + |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h) |
| +{ |
| + (*_bfd_error_handler) |
| + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), |
| + abfd, riscv_elf_rtype_to_howto (r_type)->name, |
| + h != NULL ? h->root.root.string : "a local symbol"); |
| + bfd_set_error (bfd_error_bad_value); |
| + return FALSE; |
| +} |
| +/* Look through the relocs for a section during the first phase, and |
| + allocate space in the global offset table or procedure linkage |
| + table. */ |
| + |
| +static bfd_boolean |
| +riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, |
| + asection *sec, const Elf_Internal_Rela *relocs) |
| +{ |
| + struct riscv_elf_link_hash_table *htab; |
| + Elf_Internal_Shdr *symtab_hdr; |
| + struct elf_link_hash_entry **sym_hashes; |
| + const Elf_Internal_Rela *rel; |
| + asection *sreloc = NULL; |
| + |
| + if (info->relocatable) |
| + return TRUE; |
| + |
| + htab = riscv_elf_hash_table (info); |
| + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| + sym_hashes = elf_sym_hashes (abfd); |
| + |
| + if (htab->elf.dynobj == NULL) |
| + htab->elf.dynobj = abfd; |
| + |
| + for (rel = relocs; rel < relocs + sec->reloc_count; rel++) |
| + { |
| + unsigned int r_type; |
| + unsigned long r_symndx; |
| + struct elf_link_hash_entry *h; |
| + |
| + r_symndx = ELFNN_R_SYM (rel->r_info); |
| + r_type = ELFNN_R_TYPE (rel->r_info); |
| + |
| + if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) |
| + { |
| + (*_bfd_error_handler) (_("%B: bad symbol index: %d"), |
| + abfd, r_symndx); |
| + return FALSE; |
| + } |
| + |
| + if (r_symndx < symtab_hdr->sh_info) |
| + h = NULL; |
| + else |
| + { |
| + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
| + 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; |
| + |
| + /* PR15323, ref flags aren't set for references in the same |
| + object. */ |
| + h->root.non_ir_ref = 1; |
| + } |
| + |
| + switch (r_type) |
| + { |
| + case R_RISCV_TLS_GD_HI20: |
| + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) |
| + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_GD)) |
| + return FALSE; |
| + break; |
| + |
| + case R_RISCV_TLS_GOT_HI20: |
| + if (info->shared) |
| + info->flags |= DF_STATIC_TLS; |
| + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) |
| + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_IE)) |
| + return FALSE; |
| + break; |
| + |
| + case R_RISCV_GOT_HI20: |
| + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) |
| + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_NORMAL)) |
| + return FALSE; |
| + break; |
| + |
| + case R_RISCV_CALL_PLT: |
| + /* This symbol requires a procedure linkage table entry. We |
| + actually build the entry in adjust_dynamic_symbol, |
| + because this might be a case of linking PIC code without |
| + linking in any dynamic objects, in which case we don't |
| + need to generate a procedure linkage table after all. */ |
| + |
| + if (h != NULL) |
| + { |
| + h->needs_plt = 1; |
| + h->plt.refcount += 1; |
| + } |
| + break; |
| + |
| + case R_RISCV_CALL: |
| + case R_RISCV_JAL: |
| + case R_RISCV_BRANCH: |
| + case R_RISCV_PCREL_HI20: |
| + /* In shared libs, these relocs are known to bind locally. */ |
| + if (info->shared) |
| + break; |
| + goto static_reloc; |
| + |
| + case R_RISCV_TPREL_HI20: |
| + if (!info->executable) |
| + return bad_static_reloc (abfd, r_type, h); |
| + if (h != NULL) |
| + riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_LE); |
| + goto static_reloc; |
| + |
| + case R_RISCV_HI20: |
| + if (info->shared) |
| + return bad_static_reloc (abfd, r_type, h); |
| + /* Fall through. */ |
| + |
| + case R_RISCV_COPY: |
| + case R_RISCV_JUMP_SLOT: |
| + case R_RISCV_RELATIVE: |
| + case R_RISCV_64: |
| + case R_RISCV_32: |
| + /* Fall through. */ |
| + |
| + static_reloc: |
| + if (h != NULL) |
| + h->non_got_ref = 1; |
| + |
| + if (h != NULL && !info->shared) |
| + { |
| + /* We may need a .plt entry if the function this reloc |
| + refers to is in a shared lib. */ |
| + h->plt.refcount += 1; |
| + } |
| + |
| + /* If we are creating a shared library, and this is a reloc |
| + against a global symbol, or a non PC relative reloc |
| + against a local symbol, then we need to copy the reloc |
| + into the shared library. However, if we are linking with |
| + -Bsymbolic, we do not need to copy a reloc against a |
| + global symbol which is defined in an object we are |
| + including in the link (i.e., DEF_REGULAR is set). At |
| + this point we have not seen all the input files, so it is |
| + possible that DEF_REGULAR is not set now but will be set |
| + later (it is never cleared). In case of a weak definition, |
| + DEF_REGULAR may be cleared later by a strong definition in |
| + a shared library. We account for that possibility below by |
| + storing information in the relocs_copied field of the hash |
| + table entry. A similar situation occurs when creating |
| + shared libraries and symbol visibility changes render the |
| + symbol local. |
| + |
| + If on the other hand, we are creating an executable, we |
| + may need to keep relocations for symbols satisfied by a |
| + dynamic library if we manage to avoid copy relocs for the |
| + symbol. */ |
| + if ((info->shared |
| + && (sec->flags & SEC_ALLOC) != 0 |
| + && (! riscv_elf_rtype_to_howto (r_type)->pc_relative |
| + || (h != NULL |
| + && (! info->symbolic |
| + || h->root.type == bfd_link_hash_defweak |
| + || !h->def_regular)))) |
| + || (!info->shared |
| + && (sec->flags & SEC_ALLOC) != 0 |
| + && h != NULL |
| + && (h->root.type == bfd_link_hash_defweak |
| + || !h->def_regular))) |
| + { |
| + struct riscv_elf_dyn_relocs *p; |
| + struct riscv_elf_dyn_relocs **head; |
| + |
| + /* When creating a shared object, we must copy these |
| + relocs into the output file. We create a reloc |
| + section in dynobj and make room for the reloc. */ |
| + if (sreloc == NULL) |
| + { |
| + sreloc = _bfd_elf_make_dynamic_reloc_section |
| + (sec, htab->elf.dynobj, RISCV_ELF_LOG_WORD_BYTES, |
| + abfd, /*rela?*/ TRUE); |
| + |
| + if (sreloc == NULL) |
| + return FALSE; |
| + } |
| + |
| + /* If this is a global symbol, we count the number of |
| + relocations we need for this symbol. */ |
| + if (h != NULL) |
| + head = &((struct riscv_elf_link_hash_entry *) h)->dyn_relocs; |
| + else |
| + { |
| + /* Track dynamic relocs needed for local syms too. |
| + We really need local syms available to do this |
| + easily. Oh well. */ |
| + |
| + asection *s; |
| + void *vpp; |
| + Elf_Internal_Sym *isym; |
| + |
| + isym = bfd_sym_from_r_symndx (&htab->sym_cache, |
| + abfd, r_symndx); |
| + if (isym == NULL) |
| + return FALSE; |
| + |
| + s = bfd_section_from_elf_index (abfd, isym->st_shndx); |
| + if (s == NULL) |
| + s = sec; |
| + |
| + vpp = &elf_section_data (s)->local_dynrel; |
| + head = (struct riscv_elf_dyn_relocs **) vpp; |
| + } |
| + |
| + p = *head; |
| + if (p == NULL || p->sec != sec) |
| + { |
| + bfd_size_type amt = sizeof *p; |
| + p = ((struct riscv_elf_dyn_relocs *) |
| + bfd_alloc (htab->elf.dynobj, amt)); |
| + if (p == NULL) |
| + return FALSE; |
| + p->next = *head; |
| + *head = p; |
| + p->sec = sec; |
| + p->count = 0; |
| + p->pc_count = 0; |
| + } |
| + |
| + p->count += 1; |
| + p->pc_count += riscv_elf_rtype_to_howto (r_type)->pc_relative; |
| + } |
| + |
| + break; |
| + |
| + case R_RISCV_GNU_VTINHERIT: |
| + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) |
| + return FALSE; |
| + break; |
| + |
| + case R_RISCV_GNU_VTENTRY: |
| + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) |
| + return FALSE; |
| + break; |
| + |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +static asection * |
| +riscv_elf_gc_mark_hook (asection *sec, |
| + struct bfd_link_info *info, |
| + Elf_Internal_Rela *rel, |
| + struct elf_link_hash_entry *h, |
| + Elf_Internal_Sym *sym) |
| +{ |
| + if (h != NULL) |
| + switch (ELFNN_R_TYPE (rel->r_info)) |
| + { |
| + case R_RISCV_GNU_VTINHERIT: |
| + case R_RISCV_GNU_VTENTRY: |
| + return NULL; |
| + } |
| + |
| + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); |
| +} |
| + |
| +/* Update the got entry reference counts for the section being removed. */ |
| +static bfd_boolean |
| +riscv_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, |
| + asection *sec, const Elf_Internal_Rela *relocs) |
| +{ |
| + const Elf_Internal_Rela *rel, *relend; |
| + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd); |
| + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); |
| + bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); |
| + |
| + if (info->relocatable) |
| + return TRUE; |
| + |
| + elf_section_data (sec)->local_dynrel = NULL; |
| + |
| + for (rel = relocs, relend = relocs + sec->reloc_count; rel < relend; rel++) |
| + { |
| + unsigned long r_symndx; |
| + struct elf_link_hash_entry *h = NULL; |
| + |
| + r_symndx = ELFNN_R_SYM (rel->r_info); |
| + if (r_symndx >= symtab_hdr->sh_info) |
| + { |
| + struct riscv_elf_link_hash_entry *eh; |
| + struct riscv_elf_dyn_relocs **pp; |
| + struct riscv_elf_dyn_relocs *p; |
| + |
| + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; |
| + 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; |
| + eh = (struct riscv_elf_link_hash_entry *) h; |
| + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) |
| + if (p->sec == sec) |
| + { |
| + /* Everything must go for SEC. */ |
| + *pp = p->next; |
| + break; |
| + } |
| + } |
| + |
| + switch (ELFNN_R_TYPE (rel->r_info)) |
| + { |
| + case R_RISCV_GOT_HI20: |
| + case R_RISCV_TLS_GOT_HI20: |
| + case R_RISCV_TLS_GD_HI20: |
| + if (h != NULL) |
| + { |
| + if (h->got.refcount > 0) |
| + h->got.refcount--; |
| + } |
| + else |
| + { |
| + if (local_got_refcounts && |
| + local_got_refcounts[r_symndx] > 0) |
| + local_got_refcounts[r_symndx]--; |
| + } |
| + break; |
| + |
| + case R_RISCV_HI20: |
| + case R_RISCV_PCREL_HI20: |
| + case R_RISCV_COPY: |
| + case R_RISCV_JUMP_SLOT: |
| + case R_RISCV_RELATIVE: |
| + case R_RISCV_64: |
| + case R_RISCV_32: |
| + case R_RISCV_BRANCH: |
| + case R_RISCV_CALL: |
| + case R_RISCV_JAL: |
| + if (info->shared) |
| + break; |
| + /* Fall through. */ |
| + |
| + case R_RISCV_CALL_PLT: |
| + if (h != NULL) |
| + { |
| + if (h->plt.refcount > 0) |
| + h->plt.refcount--; |
| + } |
| + break; |
| + |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + 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. */ |
| + |
| +static bfd_boolean |
| +riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
| + struct elf_link_hash_entry *h) |
| +{ |
| + struct riscv_elf_link_hash_table *htab; |
| + struct riscv_elf_link_hash_entry * eh; |
| + struct riscv_elf_dyn_relocs *p; |
| + bfd *dynobj; |
| + asection *s; |
| + |
| + htab = riscv_elf_hash_table (info); |
| + BFD_ASSERT (htab != NULL); |
| + |
| + dynobj = htab->elf.dynobj; |
| + |
| + /* 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))); |
| + |
| + /* If this is a function, put it in the procedure linkage table. We |
| + will fill in the contents of the procedure linkage table later |
| + (although we could actually do it here). */ |
| + if (h->type == STT_FUNC || h->needs_plt) |
| + { |
| + if (h->plt.refcount <= 0 |
| + || SYMBOL_CALLS_LOCAL (info, h) |
| + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT |
| + && h->root.type == bfd_link_hash_undefweak)) |
| + { |
| + /* This case can occur if we saw a R_RISCV_CALL_PLT reloc in an |
| + input file, but the symbol was never referred to by a dynamic |
| + object, or if all references were garbage collected. In such |
| + a case, we don't actually need to build a PLT entry. */ |
| + h->plt.offset = (bfd_vma) -1; |
| + h->needs_plt = 0; |
| + } |
| + |
| + return TRUE; |
| + } |
| + else |
| + h->plt.offset = (bfd_vma) -1; |
| + |
| + /* 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; |
| + } |
| + |
| + /* This is a reference to a symbol defined by a dynamic object which |
| + is not a function. */ |
| + |
| + /* If we are creating a shared library, we must presume that the |
| + only references to the symbol are via the global offset table. |
| + For such cases we need not do anything here; the relocations will |
| + be handled correctly by relocate_section. */ |
| + if (info->shared) |
| + return TRUE; |
| + |
| + /* If there are no references to this symbol that do not use the |
| + GOT, we don't need to generate a copy reloc. */ |
| + if (!h->non_got_ref) |
| + return TRUE; |
| + |
| + /* If -z nocopyreloc was given, we won't generate them either. */ |
| + if (info->nocopyreloc) |
| + { |
| + h->non_got_ref = 0; |
| + return TRUE; |
| + } |
| + |
| + eh = (struct riscv_elf_link_hash_entry *) h; |
| + for (p = eh->dyn_relocs; p != NULL; p = p->next) |
| + { |
| + s = p->sec->output_section; |
| + if (s != NULL && (s->flags & SEC_READONLY) != 0) |
| + break; |
| + } |
| + |
| + /* If we didn't find any dynamic relocs in read-only sections, then |
| + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ |
| + if (p == NULL) |
| + { |
| + h->non_got_ref = 0; |
| + 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. */ |
| + |
| + /* We must generate a R_RISCV_COPY reloc to tell the dynamic linker |
| + to copy the initial value out of the dynamic object and into the |
| + runtime process image. We need to remember the offset into the |
| + .rel.bss section we are going to use. */ |
| + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
| + { |
| + htab->srelbss->size += sizeof (ElfNN_External_Rela); |
| + h->needs_copy = 1; |
| + } |
| + |
| + if (eh->tls_type & ~GOT_NORMAL) |
| + return _bfd_elf_adjust_dynamic_copy (h, htab->sdyntdata); |
| + |
| + return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss); |
| +} |
| + |
| +/* Allocate space in .plt, .got and associated reloc sections for |
| + dynamic relocs. */ |
| + |
| +static bfd_boolean |
| +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) |
| +{ |
| + struct bfd_link_info *info; |
| + struct riscv_elf_link_hash_table *htab; |
| + struct riscv_elf_link_hash_entry *eh; |
| + struct riscv_elf_dyn_relocs *p; |
| + |
| + if (h->root.type == bfd_link_hash_indirect) |
| + return TRUE; |
| + |
| + info = (struct bfd_link_info *) inf; |
| + htab = riscv_elf_hash_table (info); |
| + BFD_ASSERT (htab != NULL); |
| + |
| + if (htab->elf.dynamic_sections_created |
| + && h->plt.refcount > 0) |
| + { |
| + /* Make sure this symbol is output as a dynamic symbol. |
| + Undefined weak syms won't yet be marked as dynamic. */ |
| + if (h->dynindx == -1 |
| + && !h->forced_local) |
| + { |
| + if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
| + return FALSE; |
| + } |
| + |
| + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) |
| + { |
| + asection *s = htab->elf.splt; |
| + |
| + if (s->size == 0) |
| + s->size = PLT_HEADER_SIZE; |
| + |
| + h->plt.offset = s->size; |
| + |
| + /* Make room for this entry. */ |
| + s->size += PLT_ENTRY_SIZE; |
| + |
| + /* We also need to make an entry in the .got.plt section. */ |
| + htab->elf.sgotplt->size += GOT_ENTRY_SIZE; |
| + |
| + /* We also need to make an entry in the .rela.plt section. */ |
| + htab->elf.srelplt->size += sizeof (ElfNN_External_Rela); |
| + |
| + /* If this symbol is not defined in a regular file, and we are |
| + not generating a shared library, then set the symbol to this |
| + location in the .plt. This is required to make function |
| + pointers compare as equal between the normal executable and |
| + the shared library. */ |
| + if (! info->shared |
| + && !h->def_regular) |
| + { |
| + h->root.u.def.section = s; |
| + h->root.u.def.value = h->plt.offset; |
| + } |
| + } |
| + else |
| + { |
| + h->plt.offset = (bfd_vma) -1; |
| + h->needs_plt = 0; |
| + } |
| + } |
| + else |
| + { |
| + h->plt.offset = (bfd_vma) -1; |
| + h->needs_plt = 0; |
| + } |
| + |
| + if (h->got.refcount > 0) |
| + { |
| + asection *s; |
| + bfd_boolean dyn; |
| + int tls_type = riscv_elf_hash_entry(h)->tls_type; |
| + |
| + /* Make sure this symbol is output as a dynamic symbol. |
| + Undefined weak syms won't yet be marked as dynamic. */ |
| + if (h->dynindx == -1 |
| + && !h->forced_local) |
| + { |
| + if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
| + return FALSE; |
| + } |
| + |
| + s = htab->elf.sgot; |
| + h->got.offset = s->size; |
| + dyn = htab->elf.dynamic_sections_created; |
| + if (tls_type & (GOT_TLS_GD | GOT_TLS_IE)) |
| + { |
| + /* TLS_GD needs two dynamic relocs and two GOT slots. */ |
| + if (tls_type & GOT_TLS_GD) |
| + { |
| + s->size += 2 * RISCV_ELF_WORD_BYTES; |
| + htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela); |
| + } |
| + |
| + /* TLS_IE needs one dynamic reloc and one GOT slot. */ |
| + if (tls_type & GOT_TLS_IE) |
| + { |
| + s->size += RISCV_ELF_WORD_BYTES; |
| + htab->elf.srelgot->size += sizeof (ElfNN_External_Rela); |
| + } |
| + } |
| + else |
| + { |
| + s->size += RISCV_ELF_WORD_BYTES; |
| + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)) |
| + htab->elf.srelgot->size += sizeof (ElfNN_External_Rela); |
| + } |
| + } |
| + else |
| + h->got.offset = (bfd_vma) -1; |
| + |
| + eh = (struct riscv_elf_link_hash_entry *) h; |
| + if (eh->dyn_relocs == NULL) |
| + return TRUE; |
| + |
| + /* In the shared -Bsymbolic case, discard space allocated for |
| + dynamic pc-relative relocs against symbols which turn out to be |
| + defined in regular objects. For the normal shared case, discard |
| + space for pc-relative relocs that have become local due to symbol |
| + visibility changes. */ |
| + |
| + if (info->shared) |
| + { |
| + if (SYMBOL_CALLS_LOCAL (info, h)) |
| + { |
| + struct riscv_elf_dyn_relocs **pp; |
| + |
| + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) |
| + { |
| + p->count -= p->pc_count; |
| + p->pc_count = 0; |
| + if (p->count == 0) |
| + *pp = p->next; |
| + else |
| + pp = &p->next; |
| + } |
| + } |
| + |
| + /* Also discard relocs on undefined weak syms with non-default |
| + visibility. */ |
| + if (eh->dyn_relocs != NULL |
| + && h->root.type == bfd_link_hash_undefweak) |
| + { |
| + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) |
| + eh->dyn_relocs = NULL; |
| + |
| + /* 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; |
| + } |
| + } |
| + } |
| + else |
| + { |
| + /* For the non-shared case, discard space for relocs against |
| + symbols which turn out to need copy relocs or are not |
| + dynamic. */ |
| + |
| + if (!h->non_got_ref |
| + && ((h->def_dynamic |
| + && !h->def_regular) |
| + || (htab->elf.dynamic_sections_created |
| + && (h->root.type == bfd_link_hash_undefweak |
| + || h->root.type == bfd_link_hash_undefined)))) |
| + { |
| + /* Make sure this symbol is output as a dynamic symbol. |
| + Undefined weak syms won't yet be marked as dynamic. */ |
| + if (h->dynindx == -1 |
| + && !h->forced_local) |
| + { |
| + if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
| + return FALSE; |
| + } |
| + |
| + /* If that succeeded, we know we'll be keeping all the |
| + relocs. */ |
| + if (h->dynindx != -1) |
| + goto keep; |
| + } |
| + |
| + eh->dyn_relocs = NULL; |
| + |
| + keep: ; |
| + } |
| + |
| + /* Finally, allocate space. */ |
| + for (p = eh->dyn_relocs; p != NULL; p = p->next) |
| + { |
| + asection *sreloc = elf_section_data (p->sec)->sreloc; |
| + sreloc->size += p->count * sizeof (ElfNN_External_Rela); |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Find any dynamic relocs that apply to read-only sections. */ |
| + |
| +static bfd_boolean |
| +readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) |
| +{ |
| + struct riscv_elf_link_hash_entry *eh; |
| + struct riscv_elf_dyn_relocs *p; |
| + |
| + eh = (struct riscv_elf_link_hash_entry *) h; |
| + for (p = eh->dyn_relocs; p != NULL; p = p->next) |
| + { |
| + asection *s = p->sec->output_section; |
| + |
| + if (s != NULL && (s->flags & SEC_READONLY) != 0) |
| + { |
| + ((struct bfd_link_info *) inf)->flags |= DF_TEXTREL; |
| + |
| + /* Short-circuit the traversal. */ |
| + return FALSE; |
| + } |
| + } |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) |
| +{ |
| + struct riscv_elf_link_hash_table *htab; |
| + bfd *dynobj; |
| + asection *s; |
| + bfd *ibfd; |
| + |
| + htab = riscv_elf_hash_table (info); |
| + BFD_ASSERT (htab != NULL); |
| + dynobj = htab->elf.dynobj; |
| + BFD_ASSERT (dynobj != NULL); |
| + |
| + if (elf_hash_table (info)->dynamic_sections_created) |
| + { |
| + /* Set the contents of the .interp section to the interpreter. */ |
| + if (info->executable) |
| + { |
| + s = bfd_get_linker_section (dynobj, ".interp"); |
| + BFD_ASSERT (s != NULL); |
| + s->size = strlen (ELFNN_DYNAMIC_INTERPRETER) + 1; |
| + s->contents = (unsigned char *) ELFNN_DYNAMIC_INTERPRETER; |
| + } |
| + } |
| + |
| + /* Set up .got offsets for local syms, and space for local dynamic |
| + relocs. */ |
| + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) |
| + { |
| + bfd_signed_vma *local_got; |
| + bfd_signed_vma *end_local_got; |
| + char *local_tls_type; |
| + bfd_size_type locsymcount; |
| + Elf_Internal_Shdr *symtab_hdr; |
| + asection *srel; |
| + |
| + if (! is_riscv_elf (ibfd)) |
| + continue; |
| + |
| + for (s = ibfd->sections; s != NULL; s = s->next) |
| + { |
| + struct riscv_elf_dyn_relocs *p; |
| + |
| + for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) |
| + { |
| + if (!bfd_is_abs_section (p->sec) |
| + && bfd_is_abs_section (p->sec->output_section)) |
| + { |
| + /* Input section has been discarded, either because |
| + it is a copy of a linkonce section or due to |
| + linker script /DISCARD/, so we'll be discarding |
| + the relocs too. */ |
| + } |
| + else if (p->count != 0) |
| + { |
| + srel = elf_section_data (p->sec)->sreloc; |
| + srel->size += p->count * sizeof (ElfNN_External_Rela); |
| + if ((p->sec->output_section->flags & SEC_READONLY) != 0) |
| + info->flags |= DF_TEXTREL; |
| + } |
| + } |
| + } |
| + |
| + local_got = elf_local_got_refcounts (ibfd); |
| + if (!local_got) |
| + continue; |
| + |
| + symtab_hdr = &elf_symtab_hdr (ibfd); |
| + locsymcount = symtab_hdr->sh_info; |
| + end_local_got = local_got + locsymcount; |
| + local_tls_type = _bfd_riscv_elf_local_got_tls_type (ibfd); |
| + s = htab->elf.sgot; |
| + srel = htab->elf.srelgot; |
| + for (; local_got < end_local_got; ++local_got, ++local_tls_type) |
| + { |
| + if (*local_got > 0) |
| + { |
| + *local_got = s->size; |
| + s->size += RISCV_ELF_WORD_BYTES; |
| + if (*local_tls_type & GOT_TLS_GD) |
| + s->size += RISCV_ELF_WORD_BYTES; |
| + if (info->shared |
| + || (*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE))) |
| + srel->size += sizeof (ElfNN_External_Rela); |
| + } |
| + else |
| + *local_got = (bfd_vma) -1; |
| + } |
| + } |
| + |
| + /* Allocate global sym .plt and .got entries, and space for global |
| + sym dynamic relocs. */ |
| + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); |
| + |
| + if (htab->elf.sgotplt) |
| + { |
| + struct elf_link_hash_entry *got; |
| + got = elf_link_hash_lookup (elf_hash_table (info), |
| + "_GLOBAL_OFFSET_TABLE_", |
| + FALSE, FALSE, FALSE); |
| + |
| + /* Don't allocate .got.plt section if there are no GOT nor PLT |
| + entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ |
| + if ((got == NULL |
| + || !got->ref_regular_nonweak) |
| + && (htab->elf.sgotplt->size == GOTPLT_HEADER_SIZE) |
| + && (htab->elf.splt == NULL |
| + || htab->elf.splt->size == 0) |
| + && (htab->elf.sgot == NULL |
| + || (htab->elf.sgot->size |
| + == get_elf_backend_data (output_bfd)->got_header_size))) |
| + htab->elf.sgotplt->size = 0; |
| + } |
| + |
| + /* 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) |
| + { |
| + if ((s->flags & SEC_LINKER_CREATED) == 0) |
| + continue; |
| + |
| + if (s == htab->elf.splt |
| + || s == htab->elf.sgot |
| + || s == htab->elf.sgotplt |
| + || s == htab->sdynbss) |
| + { |
| + /* Strip this section if we don't need it; see the |
| + comment below. */ |
| + } |
| + else if (strncmp (s->name, ".rela", 5) == 0) |
| + { |
| + if (s->size != 0) |
| + { |
| + /* We use the reloc_count field as a counter if we need |
| + to copy relocs into the output file. */ |
| + s->reloc_count = 0; |
| + } |
| + } |
| + else |
| + { |
| + /* It's not one of our sections. */ |
| + continue; |
| + } |
| + |
| + if (s->size == 0) |
| + { |
| + /* If we don't need this section, strip it from the |
| + output file. This is mostly to handle .rela.bss and |
| + .rela.plt. We must create both sections in |
| + create_dynamic_sections, because they must be created |
| + before the linker maps input sections to output |
| + sections. The linker does that before |
| + adjust_dynamic_symbol is called, and it is that |
| + function which decides whether anything needs to go |
| + into these sections. */ |
| + s->flags |= SEC_EXCLUDE; |
| + continue; |
| + } |
| + |
| + if ((s->flags & SEC_HAS_CONTENTS) == 0) |
| + continue; |
| + |
| + /* Allocate memory for the section contents. Zero the memory |
| + for the benefit of .rela.plt, which has 4 unused entries |
| + at the beginning, and we don't want garbage. */ |
| + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); |
| + if (s->contents == NULL) |
| + return FALSE; |
| + } |
| + |
| + if (elf_hash_table (info)->dynamic_sections_created) |
| + { |
| + /* Add some entries to the .dynamic section. We fill in the |
| + values later, in 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 is filled in by the |
| + dynamic linker and used by the debugger. */ |
| +#define add_dynamic_entry(TAG, VAL) \ |
| + _bfd_elf_add_dynamic_entry (info, TAG, VAL) |
| + |
| + if (info->executable) |
| + { |
| + if (!add_dynamic_entry (DT_DEBUG, 0)) |
| + return FALSE; |
| + } |
| + |
| + if (htab->elf.srelplt->size != 0) |
| + { |
| + if (!add_dynamic_entry (DT_PLTGOT, 0) |
| + || !add_dynamic_entry (DT_PLTRELSZ, 0) |
| + || !add_dynamic_entry (DT_PLTREL, DT_RELA) |
| + || !add_dynamic_entry (DT_JMPREL, 0)) |
| + return FALSE; |
| + } |
| + |
| + if (!add_dynamic_entry (DT_RELA, 0) |
| + || !add_dynamic_entry (DT_RELASZ, 0) |
| + || !add_dynamic_entry (DT_RELAENT, sizeof (ElfNN_External_Rela))) |
| + return FALSE; |
| + |
| + /* If any dynamic relocs apply to a read-only section, |
| + then we need a DT_TEXTREL entry. */ |
| + if ((info->flags & DF_TEXTREL) == 0) |
| + elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); |
| + |
| + if (info->flags & DF_TEXTREL) |
| + { |
| + if (!add_dynamic_entry (DT_TEXTREL, 0)) |
| + return FALSE; |
| + } |
| + } |
| +#undef add_dynamic_entry |
| + |
| + return TRUE; |
| +} |
| + |
| +#define TP_OFFSET 0 |
| +#define DTP_OFFSET 0x800 |
| + |
| +/* Return the relocation value for a TLS dtp-relative reloc. */ |
| + |
| +static bfd_vma |
| +dtpoff (struct bfd_link_info *info, bfd_vma address) |
| +{ |
| + /* If tls_sec is NULL, we should have signalled an error already. */ |
| + if (elf_hash_table (info)->tls_sec == NULL) |
| + return 0; |
| + return address - elf_hash_table (info)->tls_sec->vma - DTP_OFFSET; |
| +} |
| + |
| +/* Return the relocation value for a static TLS tp-relative relocation. */ |
| + |
| +static bfd_vma |
| +tpoff (struct bfd_link_info *info, bfd_vma address) |
| +{ |
| + /* If tls_sec is NULL, we should have signalled an error already. */ |
| + if (elf_hash_table (info)->tls_sec == NULL) |
| + return 0; |
| + return address - elf_hash_table (info)->tls_sec->vma - TP_OFFSET; |
| +} |
| + |
| +/* Return the global pointer's value, or 0 if it is not in use. */ |
| + |
| +static bfd_vma |
| +riscv_global_pointer_value (struct bfd_link_info *info) |
| +{ |
| + struct bfd_link_hash_entry *h; |
| + |
| + h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); |
| + if (h == NULL || h->type != bfd_link_hash_defined) |
| + return 0; |
| + |
| + return h->u.def.value + sec_addr (h->u.def.section); |
| +} |
| + |
| +/* Emplace a static relocation. */ |
| + |
| +static bfd_reloc_status_type |
| +perform_relocation (const reloc_howto_type *howto, |
| + const Elf_Internal_Rela *rel, |
| + bfd_vma value, |
| + asection *input_section, |
| + bfd *input_bfd, |
| + bfd_byte *contents) |
| +{ |
| + if (howto->pc_relative) |
| + value -= sec_addr (input_section) + rel->r_offset; |
| + value += rel->r_addend; |
| + |
| + switch (ELFNN_R_TYPE (rel->r_info)) |
| + { |
| + case R_RISCV_HI20: |
| + case R_RISCV_TPREL_HI20: |
| + case R_RISCV_PCREL_HI20: |
| + case R_RISCV_GOT_HI20: |
| + case R_RISCV_TLS_GOT_HI20: |
| + case R_RISCV_TLS_GD_HI20: |
| + value = ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)); |
| + break; |
| + |
| + case R_RISCV_LO12_I: |
| + case R_RISCV_TPREL_LO12_I: |
| + case R_RISCV_PCREL_LO12_I: |
| + value = ENCODE_ITYPE_IMM (value); |
| + break; |
| + |
| + case R_RISCV_LO12_S: |
| + case R_RISCV_TPREL_LO12_S: |
| + case R_RISCV_PCREL_LO12_S: |
| + value = ENCODE_STYPE_IMM (value); |
| + break; |
| + |
| + case R_RISCV_CALL: |
| + case R_RISCV_CALL_PLT: |
| + if (!VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value))) |
| + return bfd_reloc_overflow; |
| + value = ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)) |
| + | (ENCODE_ITYPE_IMM (value) << 32); |
| + break; |
| + |
| + case R_RISCV_JAL: |
| + if (!VALID_UJTYPE_IMM (value)) |
| + return bfd_reloc_overflow; |
| + value = ENCODE_UJTYPE_IMM (value); |
| + break; |
| + |
| + case R_RISCV_BRANCH: |
| + if (!VALID_SBTYPE_IMM (value)) |
| + return bfd_reloc_overflow; |
| + value = ENCODE_SBTYPE_IMM (value); |
| + break; |
| + |
| + case R_RISCV_32: |
| + case R_RISCV_64: |
| + case R_RISCV_ADD8: |
| + case R_RISCV_ADD16: |
| + case R_RISCV_ADD32: |
| + case R_RISCV_ADD64: |
| + case R_RISCV_SUB8: |
| + case R_RISCV_SUB16: |
| + case R_RISCV_SUB32: |
| + case R_RISCV_SUB64: |
| + case R_RISCV_TLS_DTPREL32: |
| + case R_RISCV_TLS_DTPREL64: |
| + break; |
| + |
| + default: |
| + return bfd_reloc_notsupported; |
| + } |
| + |
| + bfd_vma word = bfd_get (howto->bitsize, input_bfd, contents + rel->r_offset); |
| + word = (word & ~howto->dst_mask) | (value & howto->dst_mask); |
| + bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset); |
| + |
| + return bfd_reloc_ok; |
| +} |
| + |
| +/* Remember all PC-relative high-part relocs we've encountered to help us |
| + later resolve the corresponding low-part relocs. */ |
| + |
| +typedef struct { |
| + bfd_vma address; |
| + bfd_vma value; |
| +} riscv_pcrel_hi_reloc; |
| + |
| +typedef struct riscv_pcrel_lo_reloc { |
| + asection *input_section; |
| + struct bfd_link_info *info; |
| + reloc_howto_type *howto; |
| + const Elf_Internal_Rela *reloc; |
| + bfd_vma addr; |
| + const char *name; |
| + bfd_byte *contents; |
| + struct riscv_pcrel_lo_reloc *next; |
| +} riscv_pcrel_lo_reloc; |
| + |
| +typedef struct { |
| + htab_t hi_relocs; |
| + riscv_pcrel_lo_reloc *lo_relocs; |
| +} riscv_pcrel_relocs; |
| + |
| +static hashval_t |
| +riscv_pcrel_reloc_hash (const void *entry) |
| +{ |
| + const riscv_pcrel_hi_reloc *e = entry; |
| + return (hashval_t)(e->address >> 2); |
| +} |
| + |
| +static bfd_boolean |
| +riscv_pcrel_reloc_eq (const void *entry1, const void *entry2) |
| +{ |
| + const riscv_pcrel_hi_reloc *e1 = entry1, *e2 = entry2; |
| + return e1->address == e2->address; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_init_pcrel_relocs (riscv_pcrel_relocs *p) |
| +{ |
| + |
| + p->lo_relocs = NULL; |
| + p->hi_relocs = htab_create (1024, riscv_pcrel_reloc_hash, |
| + riscv_pcrel_reloc_eq, free); |
| + return p->hi_relocs != NULL; |
| +} |
| + |
| +static void |
| +riscv_free_pcrel_relocs (riscv_pcrel_relocs *p) |
| +{ |
| + riscv_pcrel_lo_reloc *cur = p->lo_relocs; |
| + while (cur != NULL) |
| + { |
| + riscv_pcrel_lo_reloc *next = cur->next; |
| + free (cur); |
| + cur = next; |
| + } |
| + |
| + htab_delete (p->hi_relocs); |
| +} |
| + |
| +static bfd_boolean |
| +riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr, bfd_vma value) |
| +{ |
| + riscv_pcrel_hi_reloc entry = {addr, value - addr}; |
| + riscv_pcrel_hi_reloc **slot = |
| + (riscv_pcrel_hi_reloc **) htab_find_slot (p->hi_relocs, &entry, INSERT); |
| + BFD_ASSERT (*slot == NULL); |
| + *slot = (riscv_pcrel_hi_reloc *) bfd_malloc (sizeof (riscv_pcrel_hi_reloc)); |
| + if (*slot == NULL) |
| + return FALSE; |
| + **slot = entry; |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_record_pcrel_lo_reloc (riscv_pcrel_relocs *p, |
| + asection *input_section, |
| + struct bfd_link_info *info, |
| + reloc_howto_type *howto, |
| + const Elf_Internal_Rela *reloc, |
| + bfd_vma addr, |
| + const char *name, |
| + bfd_byte *contents) |
| +{ |
| + riscv_pcrel_lo_reloc *entry; |
| + entry = (riscv_pcrel_lo_reloc *) bfd_malloc (sizeof (riscv_pcrel_lo_reloc)); |
| + if (entry == NULL) |
| + return FALSE; |
| + *entry = (riscv_pcrel_lo_reloc) {input_section, info, howto, reloc, addr, |
| + name, contents, p->lo_relocs}; |
| + p->lo_relocs = entry; |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p) |
| +{ |
| + riscv_pcrel_lo_reloc *r; |
| + for (r = p->lo_relocs; r != NULL; r = r->next) |
| + { |
| + bfd *input_bfd = r->input_section->owner; |
| + riscv_pcrel_hi_reloc search = {r->addr, 0}; |
| + riscv_pcrel_hi_reloc *entry = htab_find (p->hi_relocs, &search); |
| + if (entry == NULL) |
| + return ((*r->info->callbacks->reloc_overflow) |
| + (r->info, NULL, r->name, r->howto->name, (bfd_vma) 0, |
| + input_bfd, r->input_section, r->reloc->r_offset)); |
| + |
| + perform_relocation (r->howto, r->reloc, entry->value, r->input_section, |
| + input_bfd, r->contents); |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Relocate a RISC-V ELF section. |
| + |
| + The RELOCATE_SECTION function is called by the new ELF backend linker |
| + to handle the relocations for a section. |
| + |
| + The relocs are always passed as Rela structures. |
| + |
| + This function is responsible for adjusting the section contents as |
| + necessary, and (if generating a relocatable output file) adjusting |
| + the reloc addend as necessary. |
| + |
| + This function does not have to worry about setting the reloc |
| + address or the reloc symbol index. |
| + |
| + LOCAL_SYMS is a pointer to the swapped in local symbols. |
| + |
| + LOCAL_SECTIONS is an array giving the section in the input file |
| + corresponding to the st_shndx field of each local symbol. |
| + |
| + The global hash table entry for the global symbols can be found |
| + via elf_sym_hashes (input_bfd). |
| + |
| + When generating relocatable output, this function must handle |
| + STB_LOCAL/STT_SECTION symbols specially. The output symbol is |
| + going to be the section symbol corresponding to the output |
| + section, which means that the addend must be adjusted |
| + accordingly. */ |
| + |
| +static bfd_boolean |
| +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; |
| + Elf_Internal_Rela *relend; |
| + riscv_pcrel_relocs pcrel_relocs; |
| + bfd_boolean ret = FALSE; |
| + asection *sreloc = elf_section_data (input_section)->sreloc; |
| + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); |
| + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd); |
| + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); |
| + bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); |
| + |
| + if (!riscv_init_pcrel_relocs (&pcrel_relocs)) |
| + return FALSE; |
| + |
| + relend = relocs + input_section->reloc_count; |
| + for (rel = relocs; rel < relend; rel++) |
| + { |
| + unsigned long r_symndx; |
| + struct elf_link_hash_entry *h; |
| + Elf_Internal_Sym *sym; |
| + asection *sec; |
| + bfd_vma relocation; |
| + bfd_reloc_status_type r = bfd_reloc_ok; |
| + const char *name; |
| + bfd_vma off, ie_off; |
| + bfd_boolean unresolved_reloc, is_ie = FALSE; |
| + bfd_vma pc = sec_addr (input_section) + rel->r_offset; |
| + int r_type = ELFNN_R_TYPE (rel->r_info), tls_type; |
| + reloc_howto_type *howto = riscv_elf_rtype_to_howto (r_type); |
| + const char *msg = NULL; |
| + |
| + if (r_type == R_RISCV_GNU_VTINHERIT || r_type == R_RISCV_GNU_VTENTRY) |
| + continue; |
| + |
| + /* This is a final link. */ |
| + r_symndx = ELFNN_R_SYM (rel->r_info); |
| + h = NULL; |
| + sym = NULL; |
| + sec = NULL; |
| + unresolved_reloc = FALSE; |
| + if (r_symndx < symtab_hdr->sh_info) |
| + { |
| + sym = local_syms + r_symndx; |
| + sec = local_sections[r_symndx]; |
| + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); |
| + } |
| + else |
| + { |
| + bfd_boolean warned, ignored; |
| + |
| + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
| + r_symndx, symtab_hdr, sym_hashes, |
| + h, sec, relocation, |
| + unresolved_reloc, warned, ignored); |
| + if (warned) |
| + { |
| + /* To avoid generating warning messages about truncated |
| + relocations, set the relocation's address to be the same as |
| + the start of this section. */ |
| + if (input_section->output_section != NULL) |
| + relocation = input_section->output_section->vma; |
| + else |
| + relocation = 0; |
| + } |
| + } |
| + |
| + if (sec != NULL && discarded_section (sec)) |
| + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
| + rel, 1, relend, howto, 0, contents); |
| + |
| + if (info->relocatable) |
| + continue; |
| + |
| + if (h != NULL) |
| + name = h->root.root.string; |
| + else |
| + { |
| + name = (bfd_elf_string_from_elf_section |
| + (input_bfd, symtab_hdr->sh_link, sym->st_name)); |
| + if (name == NULL || *name == '\0') |
| + name = bfd_section_name (input_bfd, sec); |
| + } |
| + |
| + switch (r_type) |
| + { |
| + case R_RISCV_NONE: |
| + case R_RISCV_TPREL_ADD: |
| + case R_RISCV_COPY: |
| + case R_RISCV_JUMP_SLOT: |
| + case R_RISCV_RELATIVE: |
| + /* These require nothing of us at all. */ |
| + continue; |
| + |
| + case R_RISCV_BRANCH: |
| + case R_RISCV_HI20: |
| + /* These require no special handling beyond perform_relocation. */ |
| + break; |
| + |
| + case R_RISCV_GOT_HI20: |
| + if (h != NULL) |
| + { |
| + bfd_boolean dyn; |
| + |
| + off = h->got.offset; |
| + BFD_ASSERT (off != (bfd_vma) -1); |
| + dyn = elf_hash_table (info)->dynamic_sections_created; |
| + |
| + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) |
| + || (info->shared |
| + && SYMBOL_REFERENCES_LOCAL (info, h))) |
| + { |
| + /* This is actually a static link, or it is a |
| + -Bsymbolic link and the symbol is defined |
| + locally, or the symbol was forced to be local |
| + because of a version file. We must initialize |
| + this entry in the global offset table. Since the |
| + offset must always be a multiple of the word size, |
| + we use the least significant bit to record whether |
| + we have initialized it already. |
| + |
| + When doing a dynamic link, we create a .rela.got |
| + relocation entry to initialize the value. This |
| + is done in the finish_dynamic_symbol routine. */ |
| + if ((off & 1) != 0) |
| + off &= ~1; |
| + else |
| + { |
| + bfd_put_NN (output_bfd, relocation, |
| + htab->elf.sgot->contents + off); |
| + h->got.offset |= 1; |
| + } |
| + } |
| + else |
| + unresolved_reloc = FALSE; |
| + } |
| + else |
| + { |
| + BFD_ASSERT (local_got_offsets != NULL |
| + && local_got_offsets[r_symndx] != (bfd_vma) -1); |
| + |
| + off = local_got_offsets[r_symndx]; |
| + |
| + /* The offset must always be a multiple of 8 on 64-bit. |
| + We use the least significant bit to record |
| + whether we have already processed this entry. */ |
| + if ((off & 1) != 0) |
| + off &= ~1; |
| + else |
| + { |
| + if (info->shared) |
| + { |
| + asection *s; |
| + Elf_Internal_Rela outrel; |
| + |
| + /* We need to generate a R_RISCV_RELATIVE reloc |
| + for the dynamic linker. */ |
| + s = htab->elf.srelgot; |
| + BFD_ASSERT (s != NULL); |
| + |
| + outrel.r_offset = sec_addr (htab->elf.sgot) + off; |
| + outrel.r_info = |
| + ELFNN_R_INFO (0, R_RISCV_RELATIVE); |
| + outrel.r_addend = relocation; |
| + relocation = 0; |
| + riscv_elf_append_rela (output_bfd, s, &outrel); |
| + } |
| + |
| + bfd_put_NN (output_bfd, relocation, |
| + htab->elf.sgot->contents + off); |
| + local_got_offsets[r_symndx] |= 1; |
| + } |
| + } |
| + relocation = sec_addr (htab->elf.sgot) + off; |
| + if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, relocation)) |
| + r = bfd_reloc_overflow; |
| + break; |
| + |
| + case R_RISCV_ADD8: |
| + case R_RISCV_ADD16: |
| + case R_RISCV_ADD32: |
| + case R_RISCV_ADD64: |
| + { |
| + bfd_vma old_value = bfd_get (howto->bitsize, input_bfd, |
| + contents + rel->r_offset); |
| + relocation = old_value + relocation; |
| + } |
| + break; |
| + |
| + case R_RISCV_SUB8: |
| + case R_RISCV_SUB16: |
| + case R_RISCV_SUB32: |
| + case R_RISCV_SUB64: |
| + { |
| + bfd_vma old_value = bfd_get (howto->bitsize, input_bfd, |
| + contents + rel->r_offset); |
| + relocation = old_value - relocation; |
| + } |
| + break; |
| + |
| + case R_RISCV_CALL_PLT: |
| + case R_RISCV_CALL: |
| + case R_RISCV_JAL: |
| + if (info->shared && h != NULL && h->plt.offset != MINUS_ONE) |
| + { |
| + /* Refer to the PLT entry. */ |
| + relocation = sec_addr (htab->elf.splt) + h->plt.offset; |
| + unresolved_reloc = FALSE; |
| + } |
| + break; |
| + |
| + case R_RISCV_TPREL_HI20: |
| + relocation = tpoff (info, relocation); |
| + break; |
| + |
| + case R_RISCV_TPREL_LO12_I: |
| + case R_RISCV_TPREL_LO12_S: |
| + relocation = tpoff (info, relocation); |
| + if (VALID_ITYPE_IMM (relocation + rel->r_addend)) |
| + { |
| + /* We can use tp as the base register. */ |
| + bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); |
| + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); |
| + insn |= X_TP << OP_SH_RS1; |
| + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); |
| + } |
| + break; |
| + |
| + case R_RISCV_LO12_I: |
| + case R_RISCV_LO12_S: |
| + { |
| + bfd_vma gp = riscv_global_pointer_value (info); |
| + bfd_boolean x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend); |
| + if (x0_base || VALID_ITYPE_IMM (relocation + rel->r_addend - gp)) |
| + { |
| + /* We can use x0 or gp as the base register. */ |
| + bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); |
| + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); |
| + if (!x0_base) |
| + { |
| + rel->r_addend -= gp; |
| + insn |= X_GP << OP_SH_RS1; |
| + } |
| + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); |
| + } |
| + break; |
| + } |
| + |
| + case R_RISCV_PCREL_HI20: |
| + if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, |
| + relocation + rel->r_addend)) |
| + r = bfd_reloc_overflow; |
| + break; |
| + |
| + case R_RISCV_PCREL_LO12_I: |
| + case R_RISCV_PCREL_LO12_S: |
| + if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, input_section, info, |
| + howto, rel, relocation, name, |
| + contents)) |
| + continue; |
| + r = bfd_reloc_overflow; |
| + break; |
| + |
| + case R_RISCV_TLS_DTPREL32: |
| + case R_RISCV_TLS_DTPREL64: |
| + relocation = dtpoff (info, relocation); |
| + break; |
| + |
| + case R_RISCV_32: |
| + case R_RISCV_64: |
| + if ((input_section->flags & SEC_ALLOC) == 0) |
| + break; |
| + |
| + if ((info->shared |
| + && (h == NULL |
| + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT |
| + || h->root.type != bfd_link_hash_undefweak) |
| + && (! howto->pc_relative |
| + || !SYMBOL_CALLS_LOCAL (info, h))) |
| + || (!info->shared |
| + && h != NULL |
| + && h->dynindx != -1 |
| + && !h->non_got_ref |
| + && ((h->def_dynamic |
| + && !h->def_regular) |
| + || h->root.type == bfd_link_hash_undefweak |
| + || h->root.type == bfd_link_hash_undefined))) |
| + { |
| + Elf_Internal_Rela outrel; |
| + bfd_boolean skip_static_relocation, skip_dynamic_relocation; |
| + |
| + /* When generating a shared object, these relocations |
| + are copied into the output file to be resolved at run |
| + time. */ |
| + |
| + outrel.r_offset = |
| + _bfd_elf_section_offset (output_bfd, info, input_section, |
| + rel->r_offset); |
| + skip_static_relocation = outrel.r_offset != (bfd_vma) -2; |
| + skip_dynamic_relocation = outrel.r_offset >= (bfd_vma) -2; |
| + outrel.r_offset += sec_addr (input_section); |
| + |
| + if (skip_dynamic_relocation) |
| + memset (&outrel, 0, sizeof outrel); |
| + else if (h != NULL && h->dynindx != -1 |
| + && !(info->shared |
| + && SYMBOLIC_BIND (info, h) |
| + && h->def_regular)) |
| + { |
| + outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type); |
| + outrel.r_addend = rel->r_addend; |
| + } |
| + else |
| + { |
| + outrel.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE); |
| + outrel.r_addend = relocation + rel->r_addend; |
| + } |
| + |
| + riscv_elf_append_rela (output_bfd, sreloc, &outrel); |
| + if (skip_static_relocation) |
| + continue; |
| + } |
| + break; |
| + |
| + case R_RISCV_TLS_GOT_HI20: |
| + is_ie = TRUE; |
| + /* Fall through. */ |
| + |
| + case R_RISCV_TLS_GD_HI20: |
| + if (h != NULL) |
| + { |
| + off = h->got.offset; |
| + h->got.offset |= 1; |
| + } |
| + else |
| + { |
| + off = local_got_offsets[r_symndx]; |
| + local_got_offsets[r_symndx] |= 1; |
| + } |
| + |
| + tls_type = _bfd_riscv_elf_tls_type (input_bfd, h, r_symndx); |
| + BFD_ASSERT (tls_type & (GOT_TLS_IE | GOT_TLS_GD)); |
| + /* If this symbol is referenced by both GD and IE TLS, the IE |
| + reference's GOT slot follows the GD reference's slots. */ |
| + ie_off = 0; |
| + if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE)) |
| + ie_off = 2 * GOT_ENTRY_SIZE; |
| + |
| + if ((off & 1) != 0) |
| + off &= ~1; |
| + else |
| + { |
| + Elf_Internal_Rela outrel; |
| + int indx = 0; |
| + bfd_boolean need_relocs = FALSE; |
| + |
| + if (htab->elf.srelgot == NULL) |
| + abort (); |
| + |
| + if (h != NULL) |
| + { |
| + bfd_boolean dyn; |
| + dyn = htab->elf.dynamic_sections_created; |
| + |
| + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) |
| + && (!info->shared |
| + || !SYMBOL_REFERENCES_LOCAL (info, h))) |
| + { |
| + indx = h->dynindx; |
| + } |
| + } |
| + |
| + /* The GOT entries have not been initialized yet. Do it |
| + now, and emit any relocations. */ |
| + 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 (tls_type & GOT_TLS_GD) |
| + { |
| + if (need_relocs) |
| + { |
| + outrel.r_offset = sec_addr (htab->elf.sgot) + off; |
| + outrel.r_addend = 0; |
| + outrel.r_info = ELFNN_R_INFO (indx, R_RISCV_TLS_DTPMODNN); |
| + bfd_put_NN (output_bfd, 0, |
| + htab->elf.sgot->contents + off); |
| + riscv_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel); |
| + if (indx == 0) |
| + { |
| + BFD_ASSERT (! unresolved_reloc); |
| + bfd_put_NN (output_bfd, |
| + dtpoff (info, relocation), |
| + (htab->elf.sgot->contents + off + |
| + RISCV_ELF_WORD_BYTES)); |
| + } |
| + else |
| + { |
| + bfd_put_NN (output_bfd, 0, |
| + (htab->elf.sgot->contents + off + |
| + RISCV_ELF_WORD_BYTES)); |
| + outrel.r_info = ELFNN_R_INFO (indx, R_RISCV_TLS_DTPRELNN); |
| + outrel.r_offset += RISCV_ELF_WORD_BYTES; |
| + riscv_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel); |
| + } |
| + } |
| + else |
| + { |
| + /* If we are not emitting relocations for a |
| + general dynamic reference, then we must be in a |
| + static link or an executable link with the |
| + symbol binding locally. Mark it as belonging |
| + to module 1, the executable. */ |
| + bfd_put_NN (output_bfd, 1, |
| + htab->elf.sgot->contents + off); |
| + bfd_put_NN (output_bfd, |
| + dtpoff (info, relocation), |
| + (htab->elf.sgot->contents + off + |
| + RISCV_ELF_WORD_BYTES)); |
| + } |
| + } |
| + |
| + if (tls_type & GOT_TLS_IE) |
| + { |
| + if (need_relocs) |
| + { |
| + bfd_put_NN (output_bfd, 0, |
| + htab->elf.sgot->contents + off + ie_off); |
| + outrel.r_offset = sec_addr (htab->elf.sgot) |
| + + off + ie_off; |
| + outrel.r_addend = 0; |
| + if (indx == 0) |
| + outrel.r_addend = tpoff (info, relocation); |
| + outrel.r_info = ELFNN_R_INFO (indx, R_RISCV_TLS_TPRELNN); |
| + riscv_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel); |
| + } |
| + else |
| + { |
| + bfd_put_NN (output_bfd, tpoff (info, relocation), |
| + htab->elf.sgot->contents + off + ie_off); |
| + } |
| + } |
| + } |
| + |
| + BFD_ASSERT (off < (bfd_vma) -2); |
| + relocation = sec_addr (htab->elf.sgot) + off + (is_ie ? ie_off : 0); |
| + if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, relocation)) |
| + r = bfd_reloc_overflow; |
| + unresolved_reloc = FALSE; |
| + break; |
| + |
| + default: |
| + r = bfd_reloc_notsupported; |
| + } |
| + |
| + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections |
| + because such sections are not SEC_ALLOC and thus ld.so will |
| + not process them. */ |
| + if (unresolved_reloc |
| + && !((input_section->flags & SEC_DEBUGGING) != 0 |
| + && h->def_dynamic) |
| + && _bfd_elf_section_offset (output_bfd, info, input_section, |
| + rel->r_offset) != (bfd_vma) -1) |
| + { |
| + (*_bfd_error_handler) |
| + (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), |
| + input_bfd, |
| + input_section, |
| + (long) rel->r_offset, |
| + howto->name, |
| + h->root.root.string); |
| + continue; |
| + } |
| + |
| + if (r == bfd_reloc_ok) |
| + r = perform_relocation (howto, rel, relocation, input_section, |
| + input_bfd, contents); |
| + |
| + switch (r) |
| + { |
| + case bfd_reloc_ok: |
| + continue; |
| + |
| + case bfd_reloc_overflow: |
| + r = info->callbacks->reloc_overflow |
| + (info, (h ? &h->root : NULL), name, howto->name, |
| + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); |
| + break; |
| + |
| + case bfd_reloc_undefined: |
| + r = info->callbacks->undefined_symbol |
| + (info, name, input_bfd, input_section, rel->r_offset, |
| + TRUE); |
| + break; |
| + |
| + case bfd_reloc_outofrange: |
| + msg = _("internal error: out of range error"); |
| + break; |
| + |
| + case bfd_reloc_notsupported: |
| + msg = _("internal error: unsupported relocation error"); |
| + break; |
| + |
| + case bfd_reloc_dangerous: |
| + msg = _("internal error: dangerous relocation"); |
| + break; |
| + |
| + default: |
| + msg = _("internal error: unknown error"); |
| + break; |
| + } |
| + |
| + if (msg) |
| + r = info->callbacks->warning |
| + (info, msg, name, input_bfd, input_section, rel->r_offset); |
| + goto out; |
| + } |
| + |
| + ret = riscv_resolve_pcrel_lo_relocs (&pcrel_relocs); |
| +out: |
| + riscv_free_pcrel_relocs (&pcrel_relocs); |
| + return ret; |
| +} |
| + |
| +/* Finish up dynamic symbol handling. We set the contents of various |
| + dynamic sections here. */ |
| + |
| +static bfd_boolean |
| +riscv_elf_finish_dynamic_symbol (bfd *output_bfd, |
| + struct bfd_link_info *info, |
| + struct elf_link_hash_entry *h, |
| + Elf_Internal_Sym *sym) |
| +{ |
| + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); |
| + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
| + |
| + if (h->plt.offset != (bfd_vma) -1) |
| + { |
| + /* We've decided to create a PLT entry for this symbol. */ |
| + bfd_byte *loc; |
| + bfd_vma i, header_address, plt_idx, got_address; |
| + uint32_t plt_entry[PLT_ENTRY_INSNS]; |
| + Elf_Internal_Rela rela; |
| + |
| + BFD_ASSERT (h->dynindx != -1); |
| + |
| + /* Calculate the address of the PLT header. */ |
| + header_address = sec_addr (htab->elf.splt); |
| + |
| + /* Calculate the index of the entry. */ |
| + plt_idx = (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_idx, info); |
| + |
| + /* Find out where the .plt entry should go. */ |
| + loc = htab->elf.splt->contents + h->plt.offset; |
| + |
| + /* Fill in the PLT entry itself. */ |
| + riscv_make_plt_entry (got_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->elf.sgotplt->contents |
| + + (got_address - sec_addr (htab->elf.sgotplt)); |
| + bfd_put_NN (output_bfd, sec_addr (htab->elf.splt), loc); |
| + |
| + /* Fill in the entry in the .rela.plt section. */ |
| + rela.r_offset = got_address; |
| + rela.r_addend = 0; |
| + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_JUMP_SLOT); |
| + |
| + loc = htab->elf.srelplt->contents + plt_idx * sizeof (ElfNN_External_Rela); |
| + bed->s->swap_reloca_out (output_bfd, &rela, loc); |
| + |
| + if (!h->def_regular) |
| + { |
| + /* Mark the symbol as undefined, rather than as defined in |
| + the .plt section. Leave the value alone. */ |
| + sym->st_shndx = SHN_UNDEF; |
| + /* If the symbol is weak, we do need to clear the value. |
| + Otherwise, the PLT entry would provide a definition for |
| + the symbol even if the symbol wasn't defined anywhere, |
| + and so the symbol would never be NULL. */ |
| + if (!h->ref_regular_nonweak) |
| + sym->st_value = 0; |
| + } |
| + } |
| + |
| + if (h->got.offset != (bfd_vma) -1 |
| + && !(riscv_elf_hash_entry(h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE))) |
| + { |
| + asection *sgot; |
| + asection *srela; |
| + Elf_Internal_Rela rela; |
| + |
| + /* This symbol has an entry in the GOT. Set it up. */ |
| + |
| + sgot = htab->elf.sgot; |
| + srela = htab->elf.srelgot; |
| + BFD_ASSERT (sgot != NULL && srela != NULL); |
| + |
| + rela.r_offset = sec_addr (sgot) + (h->got.offset &~ (bfd_vma) 1); |
| + |
| + /* If this is a -Bsymbolic link, and the symbol is defined |
| + locally, we just want to emit a RELATIVE reloc. Likewise if |
| + the symbol was forced to be local because of a version file. |
| + The entry in the global offset table will already have been |
| + initialized in the relocate_section function. */ |
| + if (info->shared |
| + && (info->symbolic || h->dynindx == -1) |
| + && h->def_regular) |
| + { |
| + asection *sec = h->root.u.def.section; |
| + rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE); |
| + rela.r_addend = (h->root.u.def.value |
| + + sec->output_section->vma |
| + + sec->output_offset); |
| + } |
| + else |
| + { |
| + BFD_ASSERT (h->dynindx != -1); |
| + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN); |
| + rela.r_addend = 0; |
| + } |
| + |
| + bfd_put_NN (output_bfd, 0, |
| + sgot->contents + (h->got.offset & ~(bfd_vma) 1)); |
| + riscv_elf_append_rela (output_bfd, srela, &rela); |
| + } |
| + |
| + if (h->needs_copy) |
| + { |
| + Elf_Internal_Rela rela; |
| + |
| + /* This symbols needs a copy reloc. Set it up. */ |
| + BFD_ASSERT (h->dynindx != -1); |
| + |
| + rela.r_offset = sec_addr (h->root.u.def.section) + h->root.u.def.value; |
| + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_COPY); |
| + rela.r_addend = 0; |
| + riscv_elf_append_rela (output_bfd, htab->srelbss, &rela); |
| + } |
| + |
| + /* Mark some specially defined symbols as absolute. */ |
| + if (h == htab->elf.hdynamic |
| + || (h == htab->elf.hgot || h == htab->elf.hplt)) |
| + sym->st_shndx = SHN_ABS; |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Finish up the dynamic sections. */ |
| + |
| +static bfd_boolean |
| +riscv_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, |
| + bfd *dynobj, asection *sdyn) |
| +{ |
| + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); |
| + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); |
| + size_t dynsize = bed->s->sizeof_dyn; |
| + bfd_byte *dyncon, *dynconend; |
| + |
| + dynconend = sdyn->contents + sdyn->size; |
| + for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize) |
| + { |
| + Elf_Internal_Dyn dyn; |
| + asection *s; |
| + |
| + bed->s->swap_dyn_in (dynobj, dyncon, &dyn); |
| + |
| + switch (dyn.d_tag) |
| + { |
| + case DT_PLTGOT: |
| + s = htab->elf.sgotplt; |
| + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; |
| + break; |
| + case DT_JMPREL: |
| + s = htab->elf.srelplt; |
| + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; |
| + break; |
| + case DT_PLTRELSZ: |
| + s = htab->elf.srelplt; |
| + dyn.d_un.d_val = s->size; |
| + break; |
| + default: |
| + continue; |
| + } |
| + |
| + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); |
| + } |
| + return TRUE; |
| +} |
| + |
| +static bfd_boolean |
| +riscv_elf_finish_dynamic_sections (bfd *output_bfd, |
| + struct bfd_link_info *info) |
| +{ |
| + bfd *dynobj; |
| + asection *sdyn; |
| + struct riscv_elf_link_hash_table *htab; |
| + |
| + htab = riscv_elf_hash_table (info); |
| + BFD_ASSERT (htab != NULL); |
| + dynobj = htab->elf.dynobj; |
| + |
| + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
| + |
| + if (elf_hash_table (info)->dynamic_sections_created) |
| + { |
| + asection *splt; |
| + bfd_boolean ret; |
| + |
| + splt = htab->elf.splt; |
| + BFD_ASSERT (splt != NULL && sdyn != NULL); |
| + |
| + ret = riscv_finish_dyn (output_bfd, info, dynobj, sdyn); |
| + |
| + if (ret != TRUE) |
| + return ret; |
| + |
| + /* Fill in the head and tail entries in the procedure linkage table. */ |
| + if (splt->size > 0) |
| + { |
| + int i; |
| + uint32_t plt_header[PLT_HEADER_INSNS]; |
| + riscv_make_plt0_entry (sec_addr (htab->elf.sgotplt), |
| + sec_addr (splt), plt_header); |
| + |
| + for (i = 0; i < PLT_HEADER_INSNS; i++) |
| + bfd_put_32 (output_bfd, plt_header[i], splt->contents + 4*i); |
| + } |
| + |
| + elf_section_data (splt->output_section)->this_hdr.sh_entsize |
| + = PLT_ENTRY_SIZE; |
| + } |
| + |
| + if (htab->elf.sgotplt) |
| + { |
| + if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) |
| + { |
| + (*_bfd_error_handler) |
| + (_("discarded output section: `%A'"), htab->elf.sgotplt); |
| + return FALSE; |
| + } |
| + |
| + if (htab->elf.sgotplt->size > 0) |
| + { |
| + /* Write the first two entries in .got.plt, needed for the dynamic |
| + linker. */ |
| + bfd_put_NN (output_bfd, (bfd_vma) -1, htab->elf.sgotplt->contents); |
| + bfd_put_NN (output_bfd, (bfd_vma) 0, |
| + htab->elf.sgotplt->contents + GOT_ENTRY_SIZE); |
| + } |
| + |
| + elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize = |
| + GOT_ENTRY_SIZE; |
| + } |
| + |
| + if (htab->elf.sgot) |
| + { |
| + if (htab->elf.sgot->size > 0) |
| + { |
| + /* Set the first entry in the global offset table to the address of |
| + the dynamic section. */ |
| + bfd_vma val = sdyn ? sec_addr (sdyn) : 0; |
| + bfd_put_NN (output_bfd, val, htab->elf.sgot->contents); |
| + } |
| + |
| + elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = |
| + GOT_ENTRY_SIZE; |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Return address for Ith PLT stub in section PLT, for relocation REL |
| + or (bfd_vma) -1 if it should not be included. */ |
| + |
| +static bfd_vma |
| +riscv_elf_plt_sym_val (bfd_vma i, const asection *plt, |
| + const arelent *rel ATTRIBUTE_UNUSED) |
| +{ |
| + return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE; |
| +} |
| + |
| +static enum elf_reloc_type_class |
| +riscv_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| + const asection *rel_sec ATTRIBUTE_UNUSED, |
| + const Elf_Internal_Rela *rela) |
| +{ |
| + switch (ELFNN_R_TYPE (rela->r_info)) |
| + { |
| + case R_RISCV_RELATIVE: |
| + return reloc_class_relative; |
| + case R_RISCV_JUMP_SLOT: |
| + return reloc_class_plt; |
| + case R_RISCV_COPY: |
| + return reloc_class_copy; |
| + default: |
| + return reloc_class_normal; |
| + } |
| +} |
| + |
| +/* Return true if bfd machine EXTENSION is an extension of machine BASE. */ |
| + |
| +static bfd_boolean |
| +riscv_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. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) |
| +{ |
| + flagword old_flags; |
| + flagword new_flags; |
| + |
| + if (!is_riscv_elf (ibfd) || !is_riscv_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 |
| + || riscv_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; |
| + |
| + /* 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: ELF class mismatch: can't link 32- and 64-bit modules"), ibfd); |
| + goto fail; |
| + } |
| + |
| + /* 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); |
| + goto fail; |
| + } |
| + else if (EF_IS_RISCV_EXT_Xcustom(new_flags)) |
| + EF_SET_RISCV_EXT (elf_elfheader (obfd)->e_flags, |
| + EF_GET_RISCV_EXT (old_flags)); |
| + } |
| + |
| + return TRUE; |
| + |
| +fail: |
| + bfd_set_error (bfd_error_bad_value); |
| + return FALSE; |
| +} |
| + |
| +/* 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) |
| +{ |
| + unsigned int i, symcount; |
| + bfd_vma toaddr = sec->size; |
| + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); |
| + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| + unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); |
| + struct bfd_elf_section_data *data = elf_section_data (sec); |
| + bfd_byte *contents = data->this_hdr.contents; |
| + |
| + /* Actually delete the bytes. */ |
| + sec->size -= count; |
| + memmove (contents + addr, contents + addr + count, toaddr - addr - count); |
| + |
| + /* Adjust the location of all of the relocs. Note that we need not |
| + adjust the addends, since all PC-relative references must be against |
| + symbols, which we will adjust below. */ |
| + for (i = 0; i < sec->reloc_count; i++) |
| + if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr) |
| + data->relocs[i].r_offset -= count; |
| + |
| + /* Adjust the local symbols defined in this section. */ |
| + for (i = 0; i < symtab_hdr->sh_info; i++) |
| + { |
| + Elf_Internal_Sym *sym = (Elf_Internal_Sym *) symtab_hdr->contents + i; |
| + if (sym->st_shndx == sec_shndx) |
| + { |
| + /* If the symbol is in the range of memory we just moved, we |
| + have to adjust its value. */ |
| + if (sym->st_value > addr && sym->st_value <= toaddr) |
| + sym->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 (sym->st_value <= addr |
| + && sym->st_value + sym->st_size > addr |
| + && sym->st_value + sym->st_size <= toaddr) |
| + sym->st_size -= count; |
| + } |
| + } |
| + |
| + /* Now adjust the global symbols defined in this section. */ |
| + symcount = ((symtab_hdr->sh_size / sizeof(ElfNN_External_Sym)) |
| + - symtab_hdr->sh_info); |
| + |
| + for (i = 0; i < symcount; i++) |
| + { |
| + struct elf_link_hash_entry *sym_hash = sym_hashes[i]; |
| + |
| + 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; |
| +} |
| + |
| +/* Relax AUIPC + JALR into JAL. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_relax_call (bfd *abfd, asection *sec, |
| + struct bfd_link_info *link_info, |
| + Elf_Internal_Rela *rel, |
| + bfd_vma symval, |
| + bfd_boolean *again) |
| +{ |
| + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; |
| + bfd_signed_vma foff = symval - (sec_addr (sec) + rel->r_offset); |
| + bfd_boolean near_zero = !link_info->shared && symval < RISCV_IMM_REACH/2; |
| + bfd_vma auipc, jalr; |
| + int r_type; |
| + |
| + /* See if this function call can be shortened. */ |
| + if (!VALID_UJTYPE_IMM (foff) && !near_zero) |
| + return TRUE; |
| + |
| + /* Shorten the function call. */ |
| + BFD_ASSERT (rel->r_offset + 8 <= sec->size); |
| + |
| + auipc = bfd_get_32 (abfd, contents + rel->r_offset); |
| + jalr = bfd_get_32 (abfd, contents + rel->r_offset + 4); |
| + |
| + if (VALID_UJTYPE_IMM (foff)) |
| + { |
| + /* Relax to JAL rd, addr. */ |
| + r_type = R_RISCV_JAL; |
| + auipc = (jalr & (OP_MASK_RD << OP_SH_RD)) | MATCH_JAL; |
| + } |
| + else /* near_zero */ |
| + { |
| + /* Relax to JALR rd, x0, addr. */ |
| + r_type = R_RISCV_LO12_I; |
| + auipc = (jalr & (OP_MASK_RD << OP_SH_RD)) | MATCH_JALR; |
| + } |
| + |
| + /* Replace the R_RISCV_CALL reloc. */ |
| + rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), r_type); |
| + /* Replace the AUIPC. */ |
| + bfd_put_32 (abfd, auipc, contents + rel->r_offset); |
| + |
| + /* Delete unnecessary JALR. */ |
| + *again = TRUE; |
| + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 4, 4); |
| +} |
| + |
| +/* Relax non-PIC global variable references. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_relax_lui (bfd *abfd, asection *sec, |
| + struct bfd_link_info *link_info, |
| + Elf_Internal_Rela *rel, |
| + bfd_vma symval, |
| + bfd_boolean *again) |
| +{ |
| + bfd_vma gp = riscv_global_pointer_value (link_info); |
| + |
| + /* Bail out if this symbol isn't in range of either gp or x0. */ |
| + if (!VALID_ITYPE_IMM (symval - gp) && !(symval < RISCV_IMM_REACH/2)) |
| + return TRUE; |
| + |
| + /* We can delete the unnecessary AUIPC. The corresponding LO12 reloc |
| + will be converted to GPREL during relocation. */ |
| + BFD_ASSERT (rel->r_offset + 4 <= sec->size); |
| + rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); |
| + |
| + *again = TRUE; |
| + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4); |
| +} |
| + |
| +/* Relax non-PIC TLS references. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_relax_tls_le (bfd *abfd, asection *sec, |
| + struct bfd_link_info *link_info, |
| + Elf_Internal_Rela *rel, |
| + bfd_vma symval, |
| + bfd_boolean *again) |
| +{ |
| + /* See if this symbol is in range of tp. */ |
| + if (RISCV_CONST_HIGH_PART (tpoff (link_info, symval)) != 0) |
| + return TRUE; |
| + |
| + /* We can delete the unnecessary LUI and tp add. The LO12 reloc will be |
| + made directly tp-relative. */ |
| + BFD_ASSERT (rel->r_offset + 4 <= sec->size); |
| + rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); |
| + |
| + *again = TRUE; |
| + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4); |
| +} |
| + |
| +/* Implement R_RISCV_ALIGN by deleting excess alignment NOPs. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_relax_align (bfd *abfd, asection *sec, |
| + struct bfd_link_info *link_info ATTRIBUTE_UNUSED, |
| + Elf_Internal_Rela *rel, |
| + bfd_vma symval, |
| + bfd_boolean *again ATTRIBUTE_UNUSED) |
| +{ |
| + bfd_vma alignment = 1; |
| + while (alignment <= rel->r_addend) |
| + alignment *= 2; |
| + |
| + symval -= rel->r_addend; |
| + bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment; |
| + bfd_vma nop_bytes_needed = aligned_addr - symval; |
| + |
| + /* Make sure there are enough NOPs to actually achieve the alignment. */ |
| + if (rel->r_addend < nop_bytes_needed) |
| + return FALSE; |
| + |
| + /* Delete the reloc. */ |
| + rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); |
| + |
| + /* If the number of NOPs is already correct, there's nothing to do. */ |
| + if (nop_bytes_needed == rel->r_addend) |
| + return TRUE; |
| + |
| + /* Delete the excess NOPs. */ |
| + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, |
| + rel->r_addend - nop_bytes_needed); |
| +} |
| + |
| +/* Relax a section. Pass 0 shortens code sequences unless disabled. |
| + Pass 1, which cannot be disabled, handles code alignment directives. */ |
| + |
| +static bfd_boolean |
| +_bfd_riscv_relax_section (bfd *abfd, asection *sec, |
| + struct bfd_link_info *info, bfd_boolean *again) |
| +{ |
| + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd); |
| + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); |
| + struct bfd_elf_section_data *data = elf_section_data (sec); |
| + Elf_Internal_Rela *relocs; |
| + bfd_boolean ret = FALSE; |
| + unsigned int i; |
| + |
| + *again = FALSE; |
| + |
| + if (info->relocatable |
| + || (sec->flags & SEC_RELOC) == 0 |
| + || sec->reloc_count == 0 |
| + || (info->disable_target_specific_optimizations |
| + && info->relax_pass == 0)) |
| + return TRUE; |
| + |
| + /* Read this BFD's relocs if we haven't done so already. */ |
| + if (data->relocs) |
| + relocs = data->relocs; |
| + else if (!(relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, |
| + info->keep_memory))) |
| + goto fail; |
| + |
| + /* Examine and consider relaxing each reloc. */ |
| + for (i = 0; i < sec->reloc_count; i++) |
| + { |
| + Elf_Internal_Rela *rel = data->relocs + i; |
| + typeof(&_bfd_riscv_relax_call) relax_func = NULL; |
| + int type = ELFNN_R_TYPE (rel->r_info); |
| + bfd_vma symval; |
| + |
| + if (info->relax_pass == 0) |
| + { |
| + if (type == R_RISCV_CALL || type == R_RISCV_CALL_PLT) |
| + relax_func = _bfd_riscv_relax_call; |
| + else if (type == R_RISCV_HI20) |
| + relax_func = _bfd_riscv_relax_lui; |
| + else if (type == R_RISCV_TPREL_HI20 || type == R_RISCV_TPREL_ADD) |
| + relax_func = _bfd_riscv_relax_tls_le; |
| + } |
| + else if (type == R_RISCV_ALIGN) |
| + relax_func = _bfd_riscv_relax_align; |
| + |
| + if (!relax_func) |
| + continue; |
| + |
| + data->relocs = relocs; |
| + |
| + /* Read this BFD's contents if we haven't done so already. */ |
| + if (!data->this_hdr.contents |
| + && !bfd_malloc_and_get_section (abfd, sec, &data->this_hdr.contents)) |
| + goto fail; |
| + |
| + /* Read this BFD's symbols if we haven't done so already. */ |
| + if (symtab_hdr->sh_info != 0 |
| + && !symtab_hdr->contents |
| + && !(symtab_hdr->contents = |
| + (unsigned char *) bfd_elf_get_elf_syms (abfd, symtab_hdr, |
| + symtab_hdr->sh_info, |
| + 0, NULL, NULL, NULL))) |
| + goto fail; |
| + |
| + /* Get the value of the symbol referred to by the reloc. */ |
| + if (ELFNN_R_SYM (rel->r_info) < symtab_hdr->sh_info) |
| + { |
| + /* A local symbol. */ |
| + Elf_Internal_Sym *isym = ((Elf_Internal_Sym *) symtab_hdr->contents |
| + + ELFNN_R_SYM (rel->r_info)); |
| + |
| + if (isym->st_shndx == SHN_UNDEF) |
| + symval = sec_addr (sec) + rel->r_offset; |
| + else |
| + { |
| + asection *isec; |
| + BFD_ASSERT (isym->st_shndx < elf_numsections (abfd)); |
| + isec = elf_elfsections (abfd)[isym->st_shndx]->bfd_section; |
| + if (sec_addr (isec) == 0) |
| + continue; |
| + symval = sec_addr (isec) + isym->st_value; |
| + } |
| + } |
| + else |
| + { |
| + unsigned long indx; |
| + struct elf_link_hash_entry *h; |
| + |
| + indx = ELFNN_R_SYM (rel->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->elf.splt) + h->plt.offset; |
| + else if (h->root.type == bfd_link_hash_undefweak) |
| + symval = 0; |
| + 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 += rel->r_addend; |
| + |
| + if (!relax_func (abfd, sec, info, rel, symval, again)) |
| + goto fail; |
| + } |
| + |
| + ret = TRUE; |
| + |
| +fail: |
| + if (relocs != data->relocs) |
| + free (relocs); |
| + |
| + return ret; |
| +} |
| + |
| +#define ELF_ARCH bfd_arch_riscv |
| +#define ELF_TARGET_ID RISCV_ELF_DATA |
| +#define ELF_MACHINE_CODE EM_RISCV |
| +#define ELF_MAXPAGESIZE 0x2000 |
| +#define ELF_COMMONPAGESIZE 0x2000 |
| + |
| +#define TARGET_LITTLE_SYM riscv_elfNN_vec |
| +#define TARGET_LITTLE_NAME "elfNN-littleriscv" |
| + |
| +#define elf_backend_reloc_type_class riscv_reloc_type_class |
| + |
| +#define bfd_elfNN_bfd_reloc_name_lookup riscv_reloc_name_lookup |
| +#define bfd_elfNN_bfd_link_hash_table_create riscv_elf_link_hash_table_create |
| +#define bfd_elfNN_bfd_reloc_type_lookup riscv_reloc_type_lookup |
| +#define bfd_elfNN_bfd_merge_private_bfd_data \ |
| + _bfd_riscv_elf_merge_private_bfd_data |
| + |
| +#define elf_backend_copy_indirect_symbol riscv_elf_copy_indirect_symbol |
| +#define elf_backend_create_dynamic_sections riscv_elf_create_dynamic_sections |
| +#define elf_backend_check_relocs riscv_elf_check_relocs |
| +#define elf_backend_adjust_dynamic_symbol riscv_elf_adjust_dynamic_symbol |
| +#define elf_backend_size_dynamic_sections riscv_elf_size_dynamic_sections |
| +#define elf_backend_relocate_section riscv_elf_relocate_section |
| +#define elf_backend_finish_dynamic_symbol riscv_elf_finish_dynamic_symbol |
| +#define elf_backend_finish_dynamic_sections riscv_elf_finish_dynamic_sections |
| +#define elf_backend_gc_mark_hook riscv_elf_gc_mark_hook |
| +#define elf_backend_gc_sweep_hook riscv_elf_gc_sweep_hook |
| +#define elf_backend_plt_sym_val riscv_elf_plt_sym_val |
| +#define elf_info_to_howto_rel NULL |
| +#define elf_info_to_howto riscv_info_to_howto_rela |
| +#define bfd_elfNN_bfd_relax_section _bfd_riscv_relax_section |
| + |
| +#define elf_backend_init_index_section _bfd_elf_init_1_index_section |
| + |
| +#define elf_backend_can_gc_sections 1 |
| +#define elf_backend_can_refcount 1 |
| +#define elf_backend_want_got_plt 1 |
| +#define elf_backend_plt_readonly 1 |
| +#define elf_backend_plt_alignment 4 |
| +#define elf_backend_want_plt_sym 1 |
| +#define elf_backend_got_header_size (ARCH_SIZE / 8) |
| +#define elf_backend_rela_normal 1 |
| +#define elf_backend_default_execstack 0 |
| + |
| +#include "elfNN-target.h" |
| diff -urN original-binutils/bfd/elfxx-riscv.c binutils/bfd/elfxx-riscv.c |
| --- original-binutils/bfd/elfxx-riscv.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/bfd/elfxx-riscv.c 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,730 @@ |
| +/* RISC-V-specific support for ELF. |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on TILE-Gx and MIPS targets. |
| + |
| + 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" |
| +#include "elf-bfd.h" |
| +#include "elf/riscv.h" |
| +#include "opcode/riscv.h" |
| +#include "libiberty.h" |
| +#include "elfxx-riscv.h" |
| +#include <stdint.h> |
| + |
| +#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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_NONE", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_32", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0xffffffff, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_64", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* Relocation against a local symbol in a shared object. */ |
| + HOWTO (R_RISCV_RELATIVE, /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_RELATIVE", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0xffffffff, /* 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 */ |
| + |
| + /* Dynamic 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_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_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_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_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_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_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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_TLS_DTPREL64", /* name */ |
| + TRUE, /* partial_inplace */ |
| + MINUS_ONE, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + 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_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_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 (12), |
| + EMPTY_HOWTO (13), |
| + EMPTY_HOWTO (14), |
| + EMPTY_HOWTO (15), |
| + |
| + /* 12-bit PC-relative branch offset. */ |
| + HOWTO (R_RISCV_BRANCH, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 32, /* bitsize */ |
| + TRUE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_signed, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_BRANCH", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_SBTYPE_IMM(-1U),/* dst_mask */ |
| + TRUE), /* pcrel_offset */ |
| + |
| + /* 20-bit PC-relative jump offset. */ |
| + 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_JAL", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_UJTYPE_IMM(-1U), /* dst_mask */ |
| + TRUE), /* pcrel_offset */ |
| + |
| + /* 32-bit PC-relative function call (AUIPC/JALR). */ |
| + HOWTO (R_RISCV_CALL, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 64, /* bitsize */ |
| + TRUE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_CALL", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_UTYPE_IMM(-1U) | ((bfd_vma) ENCODE_ITYPE_IMM(-1U) << 32), /* dst_mask */ |
| + TRUE), /* pcrel_offset */ |
| + |
| + /* 32-bit PC-relative function call (AUIPC/JALR). */ |
| + HOWTO (R_RISCV_CALL_PLT, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 64, /* bitsize */ |
| + TRUE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_CALL_PLT", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_UTYPE_IMM(-1U) | ((bfd_vma) ENCODE_ITYPE_IMM(-1U) << 32), /* dst_mask */ |
| + TRUE), /* pcrel_offset */ |
| + |
| + /* High 20 bits of 32-bit PC-relative GOT access. */ |
| + 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_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 */ |
| + |
| + /* High 20 bits of 32-bit PC-relative TLS IE GOT access. */ |
| + 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_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 */ |
| + |
| + /* High 20 bits of 32-bit PC-relative TLS GD GOT reference. */ |
| + HOWTO (R_RISCV_TLS_GD_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_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 */ |
| + |
| + /* High 20 bits of 32-bit PC-relative reference. */ |
| + 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_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 */ |
| + |
| + /* Low 12 bits of a 32-bit PC-relative load or add. */ |
| + HOWTO (R_RISCV_PCREL_LO12_I, /* 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_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 */ |
| + |
| + /* Low 12 bits of a 32-bit PC-relative store. */ |
| + HOWTO (R_RISCV_PCREL_LO12_S, /* 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_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 */ |
| + |
| + /* High 20 bits of 32-bit absolute address. */ |
| + 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_HI20", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_UTYPE_IMM(-1U), /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* High 12 bits of 32-bit load or add. */ |
| + HOWTO (R_RISCV_LO12_I, /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_LO12_I", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_ITYPE_IMM(-1U), /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* High 12 bits of 32-bit store. */ |
| + HOWTO (R_RISCV_LO12_S, /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_LO12_S", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_STYPE_IMM(-1U), /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* High 20 bits of 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_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 */ |
| + |
| + /* Low 12 bits of TLS LE thread pointer offset for loads and adds. */ |
| + HOWTO (R_RISCV_TPREL_LO12_I, /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_TPREL_LO12_I",/* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_ITYPE_IMM(-1U), /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* Low 12 bits of TLS LE thread pointer offset for stores. */ |
| + HOWTO (R_RISCV_TPREL_LO12_S, /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_TPREL_LO12_S",/* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + ENCODE_STYPE_IMM(-1U), /* 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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_TPREL_ADD", /* name */ |
| + TRUE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 8-bit in-place addition, for local label subtraction. */ |
| + HOWTO (R_RISCV_ADD8, /* type */ |
| + 0, /* rightshift */ |
| + 0, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 32, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_ADD8", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 16-bit in-place addition, for local label subtraction. */ |
| + HOWTO (R_RISCV_ADD16, /* type */ |
| + 0, /* rightshift */ |
| + 1, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 16, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_ADD16", /* 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_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_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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_ADD64", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 8-bit in-place addition, for local label subtraction. */ |
| + HOWTO (R_RISCV_SUB8, /* type */ |
| + 0, /* rightshift */ |
| + 0, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 8, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_SUB8", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 16-bit in-place addition, for local label subtraction. */ |
| + HOWTO (R_RISCV_SUB16, /* type */ |
| + 0, /* rightshift */ |
| + 1, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 16, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_SUB16", /* 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_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_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_SUB64", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + MINUS_ONE, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* GNU extension to record C++ vtable hierarchy */ |
| + HOWTO (R_RISCV_GNU_VTINHERIT, /* type */ |
| + 0, /* rightshift */ |
| + 4, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 0, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont,/* complain_on_overflow */ |
| + NULL, /* special_function */ |
| + "R_RISCV_GNU_VTINHERIT", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* GNU extension to record C++ vtable member usage */ |
| + HOWTO (R_RISCV_GNU_VTENTRY, /* type */ |
| + 0, /* rightshift */ |
| + 4, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 0, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont,/* complain_on_overflow */ |
| + _bfd_elf_rel_vtable_reloc_fn, /* special_function */ |
| + "R_RISCV_GNU_VTENTRY", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* Indicates an alignment statement. The addend field encodes how many |
| + bytes of NOPs follow the statement. The desired alignment is the |
| + addend rounded up to the next power of two. */ |
| + HOWTO (R_RISCV_ALIGN, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 0, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_RISCV_ALIGN", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + TRUE), /* pcrel_offset */ |
| +}; |
| + |
| +/* A mapping from BFD reloc types to RISC-V 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_ADD8, R_RISCV_ADD8 }, |
| + { BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 }, |
| + { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 }, |
| + { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 }, |
| + { BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 }, |
| + { BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 }, |
| + { 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_RISCV_JMP, R_RISCV_JAL }, |
| + { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 }, |
| + { BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 }, |
| + { BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 }, |
| + { BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 }, |
| + { BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 }, |
| + { BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 }, |
| + { BFD_RELOC_RISCV_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_GOT_HI20, R_RISCV_TLS_GOT_HI20 }, |
| + { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 }, |
| + { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN }, |
| +}; |
| + |
| +/* Given a BFD reloc type, return a howto structure. */ |
| + |
| +reloc_howto_type * |
| +riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| + bfd_reloc_code_real_type code) |
| +{ |
| + unsigned int i; |
| + |
| + for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); 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_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| + const char *r_name) |
| +{ |
| + unsigned int i; |
| + |
| + for (i = 0; i < ARRAY_SIZE (howto_table); i++) |
| + if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0) |
| + return &howto_table[i]; |
| + |
| + return NULL; |
| +} |
| + |
| +reloc_howto_type * |
| +riscv_elf_rtype_to_howto (unsigned int r_type) |
| +{ |
| + if ((unsigned int)r_type >= ARRAY_SIZE (howto_table)) |
| + { |
| + (*_bfd_error_handler)(_("unrecognized relocation (0x%x)"), r_type); |
| + bfd_set_error (bfd_error_bad_value); |
| + return NULL; |
| + } |
| + return &howto_table[r_type]; |
| +} |
| diff -urN original-binutils/bfd/elfxx-riscv.h binutils/bfd/elfxx-riscv.h |
| --- original-binutils/bfd/elfxx-riscv.h 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/bfd/elfxx-riscv.h 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,34 @@ |
| +/* RISC-V ELF specific backend routines. |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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" |
| + |
| +extern reloc_howto_type * |
| +riscv_reloc_name_lookup (bfd *, const char *); |
| + |
| +extern reloc_howto_type * |
| +riscv_reloc_type_lookup (bfd *, bfd_reloc_code_real_type); |
| + |
| +extern reloc_howto_type * |
| +riscv_elf_rtype_to_howto (unsigned int r_type); |
| diff -urN original-binutils/bfd/Makefile.am binutils/bfd/Makefile.am |
| --- original-binutils/bfd/Makefile.am 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/bfd/Makefile.am 2015-03-07 09:55:02.371135671 +0100 |
| @@ -931,6 +931,18 @@ |
| sed -e s/NN/64/g < $(srcdir)/elfnn-ia64.c > elf64-ia64.new |
| mv -f elf64-ia64.new elf64-ia64.c |
| |
| +elf32-riscv.c : elfnn-riscv.c |
| + rm -f elf32-riscv.c |
| + echo "#line 1 \"$(srcdir)/elfnn-riscv.c\"" > elf32-riscv.new |
| + sed -e s/NN/32/g < $(srcdir)/elfnn-riscv.c >> elf32-riscv.new |
| + mv -f elf32-riscv.new elf32-riscv.c |
| + |
| +elf64-riscv.c : elfnn-riscv.c |
| + rm -f elf64-riscv.c |
| + echo "#line 1 \"$(srcdir)/elfnn-riscv.c\"" > elf64-riscv.new |
| + sed -e s/NN/64/g < $(srcdir)/elfnn-riscv.c >> elf64-riscv.new |
| + mv -f elf64-riscv.new elf64-riscv.c |
| + |
| peigen.c : peXXigen.c |
| rm -f peigen.c |
| sed -e s/XX/pe/g < $(srcdir)/peXXigen.c > peigen.new |
| diff -urN original-binutils/bfd/Makefile.in binutils/bfd/Makefile.in |
| --- original-binutils/bfd/Makefile.in 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/bfd/Makefile.in 2015-03-07 09:55:02.371135671 +0100 |
| @@ -2009,6 +2009,18 @@ |
| sed -e s/NN/64/g < $(srcdir)/elfnn-ia64.c > elf64-ia64.new |
| mv -f elf64-ia64.new elf64-ia64.c |
| |
| +elf32-riscv.c : elfnn-riscv.c |
| + rm -f elf32-riscv.c |
| + echo "#line 1 \"$(srcdir)/elfnn-riscv.c\"" > elf32-riscv.new |
| + sed -e s/NN/32/g < $(srcdir)/elfnn-riscv.c >> elf32-riscv.new |
| + mv -f elf32-riscv.new elf32-riscv.c |
| + |
| +elf64-riscv.c : elfnn-riscv.c |
| + rm -f elf64-riscv.c |
| + echo "#line 1 \"$(srcdir)/elfnn-riscv.c\"" > elf64-riscv.new |
| + sed -e s/NN/64/g < $(srcdir)/elfnn-riscv.c >> elf64-riscv.new |
| + mv -f elf64-riscv.new elf64-riscv.c |
| + |
| peigen.c : peXXigen.c |
| rm -f peigen.c |
| sed -e s/XX/pe/g < $(srcdir)/peXXigen.c > peigen.new |
| diff -urN original-binutils/bfd/targets.c binutils/bfd/targets.c |
| --- original-binutils/bfd/targets.c 2014-11-04 10:54:41.000000000 +0100 |
| +++ binutils-2.25/bfd/targets.c 2015-03-07 09:55:02.371135671 +0100 |
| @@ -784,6 +784,8 @@ |
| extern const bfd_target powerpc_pei_vec; |
| extern const bfd_target powerpc_pei_le_vec; |
| extern const bfd_target powerpc_xcoff_vec; |
| +extern const bfd_target riscv_elf32_vec; |
| +extern const bfd_target riscv_elf64_vec; |
| extern const bfd_target rl78_elf32_vec; |
| extern const bfd_target rs6000_xcoff64_vec; |
| extern const bfd_target rs6000_xcoff64_aix_vec; |
| diff -urN original-binutils/binutils/readelf.c binutils/binutils/readelf.c |
| --- original-binutils/binutils/readelf.c 2014-12-23 09:47:10.000000000 +0100 |
| +++ binutils-2.25/binutils/readelf.c 2015-03-07 09:55:02.375135671 +0100 |
| @@ -125,6 +125,7 @@ |
| #include "elf/metag.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" |
| @@ -720,6 +721,7 @@ |
| case EM_OR1K: |
| case EM_PPC64: |
| case EM_PPC: |
| + case EM_RISCV: |
| case EM_RL78: |
| case EM_RX: |
| case EM_S390: |
| @@ -1252,6 +1254,10 @@ |
| 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; |
| @@ -2164,6 +2170,7 @@ |
| case EM_CR16: |
| case EM_MICROBLAZE: |
| case EM_MICROBLAZE_OLD: return "Xilinx MicroBlaze"; |
| + case EM_RISCV: return "RISC-V"; |
| case EM_RL78: return "Renesas RL78"; |
| case EM_RX: return "Renesas RX"; |
| case EM_METAG: return "Imagination Technologies Meta processor architecture"; |
| @@ -2951,6 +2958,14 @@ |
| decode_NDS32_machine_flags (e_flags, buf, sizeof buf); |
| 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)) |
| { |
| @@ -10789,6 +10804,8 @@ |
| return reloc_type == 1; /* R_PPC64_ADDR32. */ |
| case EM_PPC: |
| return reloc_type == 1; /* R_PPC_ADDR32. */ |
| + case EM_RISCV: |
| + return reloc_type == 1; /* R_RISCV_32. */ |
| case EM_RL78: |
| return reloc_type == 1; /* R_RL78_DIR32. */ |
| case EM_RX: |
| @@ -10924,6 +10941,8 @@ |
| return reloc_type == 80; /* R_PARISC_DIR64. */ |
| case EM_PPC64: |
| return reloc_type == 38; /* R_PPC64_ADDR64. */ |
| + case EM_RISCV: |
| + return reloc_type == 2; /* R_RISCV_64. */ |
| case EM_SPARC32PLUS: |
| case EM_SPARCV9: |
| case EM_SPARC: |
| @@ -11072,6 +11091,7 @@ |
| case EM_ADAPTEVA_EPIPHANY: |
| case EM_PPC: /* R_PPC_NONE. */ |
| case EM_PPC64: /* R_PPC64_NONE. */ |
| + case EM_RISCV: /* R_RISCV_NONE. */ |
| case EM_ARM: /* R_ARM_NONE. */ |
| case EM_IA_64: /* R_IA64_NONE. */ |
| case EM_SH: /* R_SH_NONE. */ |
| diff -urN original-binutils/config.sub binutils/config.sub |
| --- original-binutils/config.sub 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/config.sub 2015-03-07 09:55:02.375135671 +0100 |
| @@ -335,6 +335,9 @@ |
| ms1) |
| basic_machine=mt-unknown |
| ;; |
| + riscv) |
| + basic_machine=riscv-ucb |
| + ;; |
| |
| strongarm | thumb | xscale) |
| basic_machine=arm-unknown |
| diff -urN original-binutils/gas/config/tc-riscv.c binutils/gas/config/tc-riscv.c |
| --- original-binutils/gas/config/tc-riscv.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/gas/config/tc-riscv.c 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,2225 @@ |
| +/* tc-riscv.c -- RISC-V assembler |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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 "elf/riscv.h" |
| +#include "opcode/riscv.h" |
| + |
| +#include <execinfo.h> |
| +#include <stdint.h> |
| + |
| +/* Information about an instruction, including its format, operands |
| + and fixups. */ |
| +struct riscv_cl_insn |
| +{ |
| + /* The opcode's entry in riscv_opcodes. */ |
| + const struct riscv_opcode *insn_mo; |
| + |
| + /* The encoded instruction bits. */ |
| + 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; |
| +}; |
| + |
| +bfd_boolean rv64 = TRUE; /* RV64 (true) or RV32 (false) */ |
| +#define LOAD_ADDRESS_INSN (rv64 ? "ld" : "lw") |
| +#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 riscv_set_options |
| +{ |
| + /* Generate position-independent code. */ |
| + int pic; |
| + /* Generate RVC code. */ |
| + int rvc; |
| +}; |
| + |
| +static struct riscv_set_options riscv_opts = |
| +{ |
| + 0, /* pic */ |
| + 0, /* rvc */ |
| +}; |
| + |
| +/* 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; |
| + |
| +#define RELAX_BRANCH_ENCODE(uncond, toofar) \ |
| + ((relax_substateT) \ |
| + (0xc0000000 \ |
| + | ((toofar) ? 1 : 0) \ |
| + | ((uncond) ? 2 : 0))) |
| +#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000) |
| +#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0) |
| +#define RELAX_BRANCH_UNCOND(i) (((i) & 2) != 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) & ~((insn_t)(MASK) << (SHIFT))) \ |
| + | ((insn_t)((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 riscv_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 riscv_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__) |
| + |
| +static char *expr_end; |
| + |
| +/* Expressions which appear in instructions. These are set by |
| + riscv_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 * |
| +riscv_target_format (void) |
| +{ |
| + return rv64 ? "elf64-littleriscv" : "elf32-littleriscv"; |
| +} |
| + |
| +/* Return the length of instruction INSN. */ |
| + |
| +static inline unsigned int |
| +insn_length (const struct riscv_cl_insn *insn) |
| +{ |
| + return riscv_insn_length (insn->insn_opcode); |
| +} |
| + |
| +/* Initialise INSN from opcode entry MO. Leave its position unspecified. */ |
| + |
| +static void |
| +create_insn (struct riscv_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 riscv_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 riscv_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 riscv_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 riscv_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); |
| +} |
| + |
| +/* 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 = TRUE; |
| + |
| + if (fragp) |
| + { |
| + bfd_boolean uncond = RELAX_BRANCH_UNCOND (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) |
| + 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, toofar); |
| + } |
| + |
| + return toofar ? 8 : 4; |
| +} |
| + |
| +struct regname { |
| + const char *name; |
| + unsigned int num; |
| +}; |
| + |
| +enum reg_class { |
| + RCLASS_GPR, |
| + RCLASS_FPR, |
| + RCLASS_CSR, |
| + RCLASS_VEC_GPR, |
| + RCLASS_VEC_FPR, |
| + RCLASS_MAX |
| +}; |
| + |
| +static struct hash_control *reg_names_hash = NULL; |
| + |
| +#define ENCODE_REG_HASH(cls, n) (void*)(uintptr_t)((n)*RCLASS_MAX + (cls) + 1) |
| +#define DECODE_REG_CLASS(hash) (((uintptr_t)(hash) - 1) % RCLASS_MAX) |
| +#define DECODE_REG_NUM(hash) (((uintptr_t)(hash) - 1) / RCLASS_MAX) |
| + |
| +static void |
| +hash_reg_name (enum reg_class class, const char *name, unsigned n) |
| +{ |
| + void *hash = ENCODE_REG_HASH (class, n); |
| + const char *retval = hash_insert (reg_names_hash, name, hash); |
| + if (retval != NULL) |
| + as_fatal (_("internal error: can't hash `%s': %s"), name, retval); |
| +} |
| + |
| +static void |
| +hash_reg_names (enum reg_class class, const char * const names[], unsigned n) |
| +{ |
| + unsigned i; |
| + for (i = 0; i < n; i++) |
| + hash_reg_name (class, names[i], i); |
| +} |
| + |
| +static unsigned int |
| +reg_lookup_internal (const char *s, enum reg_class class) |
| +{ |
| + struct regname *r = (struct regname *) hash_find (reg_names_hash, s); |
| + if (r == NULL || DECODE_REG_CLASS (r) != class) |
| + return -1; |
| + return DECODE_REG_NUM (r); |
| +} |
| + |
| +static int |
| +reg_lookup (char **s, enum reg_class class, unsigned int *regnop) |
| +{ |
| + 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. Advance to next token if one was recognized. */ |
| + if ((reg = reg_lookup_internal (*s, class)) >= 0) |
| + *s = e; |
| + |
| + *e = save_c; |
| + if (regnop) |
| + *regnop = reg; |
| + return reg >= 0; |
| +} |
| + |
| +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; |
| +} |
| + |
| +/* 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_riscv_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 RISC-V opcode (mask error): %s %s"), |
| + opc->name, opc->args); |
| + return 0; |
| + } |
| + required_bits = ((insn_t)1 << (8 * riscv_insn_length (opc->match))) - 1; |
| + /* Work around for undefined behavior of uint64_t << 64 */ |
| + if(riscv_insn_length (opc->match) == 8) |
| + required_bits = 0xffffffffffffffff; |
| + |
| +#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 RISC-V 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 RISC-V 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 RISC-V 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; |
| +}; |
| + |
| +/* 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_riscv_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 (); |
| + hash_reg_names (RCLASS_GPR, riscv_gpr_names_numeric, NGPR); |
| + hash_reg_names (RCLASS_GPR, riscv_gpr_names_abi, NGPR); |
| + hash_reg_names (RCLASS_FPR, riscv_fpr_names_numeric, NFPR); |
| + hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR); |
| + hash_reg_names (RCLASS_VEC_GPR, riscv_vec_gpr_names, NVGPR); |
| + hash_reg_names (RCLASS_VEC_FPR, riscv_vec_fpr_names, NVFPR); |
| + |
| +#define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num); |
| +#include "opcode/riscv-opc.h" |
| +#undef DECLARE_CSR |
| + |
| + /* set the default alignment for the text section (2**2) */ |
| + record_alignment (text_section, 2); |
| +} |
| + |
| +/* 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 riscv_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 (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_CONST_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), |
| + 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 RISC-V 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_RISCV_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; |
| + } |
| + } |
| + |
| + add_fixed_insn (ip); |
| + |
| + install_insn (ip); |
| +} |
| + |
| +/* 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 riscv_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 || ex->X_op == O_symbol) |
| + && IS_ZEXT_32BIT_NUM (ex->X_add_number)) |
| + ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000) |
| + - 0x80000000); |
| +} |
| + |
| +static symbolS * |
| +make_internal_label (void) |
| +{ |
| + return (symbolS *) local_symbol_make (FAKE_LABEL_NAME, now_seg, |
| + (valueT) frag_now_fix(), frag_now); |
| +} |
| + |
| +/* 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) |
| +{ |
| + expressionS ep2; |
| + ep2.X_op = O_symbol; |
| + ep2.X_add_symbol = make_internal_label (); |
| + ep2.X_add_number = 0; |
| + |
| + macro_build (ep, "auipc", "d,u", tempreg, hi_reloc); |
| + macro_build (&ep2, 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); |
| +} |
| + |
| +/* 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 riscv_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 an integer constant into a register. */ |
| + |
| +static void |
| +load_const (int reg, expressionS *ep) |
| +{ |
| + int shift = RISCV_IMM_BITS; |
| + expressionS upper = *ep, lower = *ep; |
| + lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift); |
| + upper.X_add_number -= lower.X_add_number; |
| + |
| + gas_assert (ep->X_op == O_constant); |
| + |
| + if (rv64 && !IS_SEXT_32BIT_NUM(ep->X_add_number)) |
| + { |
| + /* Reduce to a signed 32-bit constant using SLLI and ADDI, which |
| + is not optimal but also not so bad. */ |
| + while (((upper.X_add_number >> shift) & 1) == 0) |
| + shift++; |
| + |
| + upper.X_add_number = (int64_t) upper.X_add_number >> shift; |
| + load_const(reg, &upper); |
| + |
| + macro_build (NULL, "slli", "d,s,>", reg, reg, shift); |
| + if (lower.X_add_number != 0) |
| + macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_RISCV_LO12_I); |
| + } |
| + else |
| + { |
| + int hi_reg = 0; |
| + |
| + if (upper.X_add_number != 0) |
| + { |
| + macro_build (ep, "lui", "d,u", reg, BFD_RELOC_RISCV_HI20); |
| + hi_reg = reg; |
| + } |
| + |
| + if (lower.X_add_number != 0 || hi_reg == 0) |
| + macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg, |
| + BFD_RELOC_RISCV_LO12_I); |
| + } |
| +} |
| + |
| +/* Expand RISC-V assembly macros into one or more instructions. */ |
| +static void |
| +macro (struct riscv_cl_insn *ip) |
| +{ |
| + int rd = (ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD; |
| + int rs1 = (ip->insn_opcode >> OP_SH_RS1) & OP_MASK_RS1; |
| + int rs2 = (ip->insn_opcode >> OP_SH_RS2) & OP_MASK_RS2; |
| + int 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 (riscv_opts.pic && mask == M_LA) /* Global PIC symbol */ |
| + pcrel_load (rd, rd, &offset_expr, LOAD_ADDRESS_INSN, |
| + BFD_RELOC_RISCV_GOT_HI20, BFD_RELOC_RISCV_PCREL_LO12_I); |
| + 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_PCREL_LO12_I); |
| + break; |
| + |
| + case M_LA_TLS_IE: |
| + pcrel_load (rd, rd, &offset_expr, LOAD_ADDRESS_INSN, |
| + BFD_RELOC_RISCV_TLS_GOT_HI20, BFD_RELOC_RISCV_PCREL_LO12_I); |
| + 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_access (0, rs1, &offset_expr, "vf", "s,s,q", |
| + BFD_RELOC_RISCV_PCREL_HI20, BFD_RELOC_RISCV_PCREL_LO12_S); |
| + break; |
| + |
| + case M_CALL: |
| + riscv_call (rd, rs1, &offset_expr, offset_reloc); |
| + break; |
| + |
| + default: |
| + as_bad (_("Macro %s not implemented"), ip->insn_mo->name); |
| + break; |
| + } |
| +} |
| + |
| +static const struct percent_op_match percent_op_utype[] = |
| +{ |
| + {"%tprel_hi", BFD_RELOC_RISCV_TPREL_HI20}, |
| + {"%pcrel_hi", BFD_RELOC_RISCV_PCREL_HI20}, |
| + {"%tls_ie_pcrel_hi", BFD_RELOC_RISCV_TLS_GOT_HI20}, |
| + {"%tls_gd_pcrel_hi", BFD_RELOC_RISCV_TLS_GD_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}, |
| + {"%pcrel_lo", BFD_RELOC_RISCV_PCREL_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}, |
| + {"%pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_S}, |
| + {0, 0} |
| +}; |
| + |
| +static const struct percent_op_match percent_op_rtype[] = |
| +{ |
| + {"%tprel_add", BFD_RELOC_RISCV_TPREL_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; |
| +} |
| + |
| +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; |
| +} |
| + |
| +/* 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 |
| +riscv_ip (char *str, struct riscv_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; |
| + 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, RCLASS_VEC_GPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VRD, *ip, regno ); |
| + continue; |
| + case 's': |
| + ok = reg_lookup( &s, RCLASS_VEC_GPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VRS, *ip, regno ); |
| + continue; |
| + case 't': |
| + ok = reg_lookup( &s, RCLASS_VEC_GPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VRT, *ip, regno ); |
| + continue; |
| + case 'r': |
| + ok = reg_lookup( &s, RCLASS_VEC_GPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VRR, *ip, regno ); |
| + continue; |
| + case 'D': |
| + ok = reg_lookup( &s, RCLASS_VEC_FPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VFD, *ip, regno ); |
| + continue; |
| + case 'S': |
| + ok = reg_lookup( &s, RCLASS_VEC_FPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VFS, *ip, regno ); |
| + continue; |
| + case 'T': |
| + ok = reg_lookup( &s, RCLASS_VEC_FPR, ®no ); |
| + if ( !ok ) |
| + as_bad( _( "Invalid vector register" ) ); |
| + INSERT_OPERAND( VFT, *ip, regno ); |
| + continue; |
| + case 'R': |
| + ok = reg_lookup( &s, RCLASS_VEC_FPR, ®no ); |
| + 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 '<': /* shift amount, 0 - 31 */ |
| + 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 - (XLEN-1) */ |
| + 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, RCLASS_CSR, ®no); |
| + if (ok) |
| + INSERT_OPERAND (CSR, *ip, regno); |
| + else |
| + { |
| + my_getExpression (&imm_expr, s); |
| + check_absolute_expr (ip, &imm_expr); |
| + if ((unsigned long) imm_expr.X_add_number > 0xfff) |
| + as_warn(_("Improper CSR address (%lu)"), |
| + (unsigned long) imm_expr.X_add_number); |
| + INSERT_OPERAND (CSR, *ip, imm_expr.X_add_number); |
| + imm_expr.X_op = O_absent; |
| + s = expr_end; |
| + } |
| + continue; |
| + |
| + case 'm': /* rounding mode */ |
| + if (arg_lookup (&s, riscv_rm, ARRAY_SIZE(riscv_rm), ®no)) |
| + { |
| + 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), ®no)) |
| + { |
| + 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, RCLASS_GPR, ®no); |
| + 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 */ |
| + if (reg_lookup (&s, RCLASS_FPR, ®no)) |
| + { |
| + 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_constant_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_RISCV_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; |
| + } |
| +} |
| + |
| +void |
| +md_assemble (char *str) |
| +{ |
| + struct riscv_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; |
| + |
| + riscv_ip (str, &insn); |
| + |
| + 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); |
| + } |
| +} |
| + |
| +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 OPTION_MRVC: |
| + riscv_opts.rvc = 1; |
| + break; |
| + |
| + case OPTION_MNO_RVC: |
| + riscv_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: |
| + riscv_opts.pic = FALSE; |
| + break; |
| + |
| + case OPTION_PIC: |
| + riscv_opts.pic = TRUE; |
| + break; |
| + |
| + default: |
| + return 0; |
| + } |
| + |
| + return 1; |
| +} |
| + |
| +void |
| +riscv_after_parse_args (void) |
| +{ |
| + if (riscv_subsets == NULL) |
| + riscv_set_arch("RVIMAFDXcustom"); |
| +} |
| + |
| +void |
| +riscv_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); |
| + |
| + /* Remember value for tc_gen_reloc. */ |
| + fixP->fx_addnumber = *valP; |
| + |
| + switch (fixP->fx_r_type) |
| + { |
| + case BFD_RELOC_RISCV_TLS_GOT_HI20: |
| + case BFD_RELOC_RISCV_TLS_GD_HI20: |
| + case BFD_RELOC_RISCV_TLS_DTPREL32: |
| + case BFD_RELOC_RISCV_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: |
| + S_SET_THREAD_LOCAL (fixP->fx_addsy); |
| + /* fall through */ |
| + |
| + 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_ADD8: |
| + case BFD_RELOC_RISCV_ADD16: |
| + case BFD_RELOC_RISCV_ADD32: |
| + case BFD_RELOC_RISCV_ADD64: |
| + case BFD_RELOC_RISCV_SUB8: |
| + case BFD_RELOC_RISCV_SUB16: |
| + 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. */ |
| + break; |
| + |
| + case BFD_RELOC_64: |
| + case BFD_RELOC_32: |
| + case BFD_RELOC_16: |
| + case BFD_RELOC_8: |
| + 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 if (fixP->fx_r_type == BFD_RELOC_32) |
| + fixP->fx_r_type = BFD_RELOC_RISCV_ADD32, |
| + fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB32; |
| + else if (fixP->fx_r_type == BFD_RELOC_16) |
| + fixP->fx_r_type = BFD_RELOC_RISCV_ADD16, |
| + fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB16; |
| + else |
| + fixP->fx_r_type = BFD_RELOC_RISCV_ADD8, |
| + fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB8; |
| + } |
| + /* 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; |
| + } |
| + break; |
| + |
| + case BFD_RELOC_RISCV_JMP: |
| + if (fixP->fx_addsy) |
| + { |
| + /* Fill in a tentative value to improve objdump readability. */ |
| + bfd_vma delta = ENCODE_UJTYPE_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP); |
| + bfd_putl32 (bfd_getl32 (buf) | delta, buf); |
| + } |
| + break; |
| + |
| + case BFD_RELOC_12_PCREL: |
| + if (fixP->fx_addsy) |
| + { |
| + /* Fill in a tentative value to improve objdump readability. */ |
| + bfd_vma delta = ENCODE_SBTYPE_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP); |
| + bfd_putl32 (bfd_getl32 (buf) | delta, buf); |
| + } |
| + break; |
| + |
| + case BFD_RELOC_RISCV_PCREL_LO12_S: |
| + case BFD_RELOC_RISCV_PCREL_LO12_I: |
| + case BFD_RELOC_RISCV_CALL: |
| + case BFD_RELOC_RISCV_CALL_PLT: |
| + case BFD_RELOC_RISCV_ALIGN: |
| + break; |
| + |
| + default: |
| + /* We ignore generic BFD relocations we don't know about. */ |
| + if (bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type) != NULL) |
| + internalError (); |
| + } |
| +} |
| + |
| +/* This structure is used to hold a stack of .set values. */ |
| + |
| +struct riscv_option_stack |
| +{ |
| + struct riscv_option_stack *next; |
| + struct riscv_set_options options; |
| +}; |
| + |
| +static struct riscv_option_stack *riscv_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) |
| + riscv_opts.rvc = 1; |
| + else if (strcmp (name, "norvc") == 0) |
| + riscv_opts.rvc = 0; |
| + else if (strcmp (name, "push") == 0) |
| + { |
| + struct riscv_option_stack *s; |
| + |
| + s = (struct riscv_option_stack *) xmalloc (sizeof *s); |
| + s->next = riscv_opts_stack; |
| + s->options = riscv_opts; |
| + riscv_opts_stack = s; |
| + } |
| + else if (strcmp (name, "pop") == 0) |
| + { |
| + struct riscv_option_stack *s; |
| + |
| + s = riscv_opts_stack; |
| + if (s == NULL) |
| + as_bad (_(".option pop with no .option push")); |
| + else |
| + { |
| + riscv_opts = s->options; |
| + riscv_opts_stack = s->next; |
| + free (s); |
| + } |
| + } |
| + else |
| + { |
| + as_warn (_("Unrecognized .option directive: %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 (int 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_RISCV_TLS_DTPREL64 |
| + : BFD_RELOC_RISCV_TLS_DTPREL32)); |
| + |
| + demand_empty_rest_of_line (); |
| +} |
| + |
| +/* Handle the .bss pseudo-op. */ |
| + |
| +static void |
| +s_bss (int ignore ATTRIBUTE_UNUSED) |
| +{ |
| + subseg_set (bss_section, 0); |
| + demand_empty_rest_of_line (); |
| +} |
| + |
| +/* Align to a given power of two. */ |
| + |
| +static void |
| +s_align (int x ATTRIBUTE_UNUSED) |
| +{ |
| + int alignment, fill_value = 0, fill_value_specified = 0; |
| + |
| + alignment = get_absolute_expression (); |
| + if (alignment < 0 || alignment > 31) |
| + as_bad (_("unsatisfiable alignment: %d"), alignment); |
| + |
| + if (*input_line_pointer == ',') |
| + { |
| + ++input_line_pointer; |
| + fill_value = get_absolute_expression (); |
| + fill_value_specified = 1; |
| + } |
| + |
| + if (!fill_value_specified && subseg_text_p (now_seg) && alignment > 2) |
| + { |
| + /* Emit the worst-case NOP string. The linker will delete any |
| + unnecessary NOPs. This allows us to support code alignment |
| + in spite of linker relaxations. */ |
| + bfd_vma i, worst_case_nop_bytes = (1L << alignment) - 4; |
| + char *nops = frag_more (worst_case_nop_bytes); |
| + for (i = 0; i < worst_case_nop_bytes; i += 4) |
| + md_number_to_chars (nops + i, RISCV_NOP, 4); |
| + |
| + expressionS ex; |
| + ex.X_op = O_constant; |
| + ex.X_add_number = worst_case_nop_bytes; |
| + |
| + fix_new_exp (frag_now, nops - frag_now->fr_literal, 0, |
| + &ex, TRUE, BFD_RELOC_RISCV_ALIGN); |
| + } |
| + else if (alignment) |
| + frag_align (alignment, fill_value, 0); |
| + |
| + record_alignment (now_seg, alignment); |
| + |
| + demand_empty_rest_of_line (); |
| +} |
| + |
| +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) |
| +{ |
| + arelent *reloc = (arelent *) xmalloc (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; |
| + |
| + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); |
| + if (reloc->howto == NULL) |
| + { |
| + if ((fixp->fx_r_type == BFD_RELOC_16 || fixp->fx_r_type == BFD_RELOC_8) |
| + && fixp->fx_addsy != NULL && fixp->fx_subsy != NULL) |
| + { |
| + /* We don't have R_RISCV_8/16, but for this special case, |
| + we can use R_RISCV_ADD8/16 with R_RISCV_SUB8/16. */ |
| + return reloc; |
| + } |
| + |
| + as_bad_where (fixp->fx_file, fixp->fx_line, |
| + _("cannot represent %s relocation in object file"), |
| + bfd_get_reloc_code_name (fixp->fx_r_type)); |
| + return NULL; |
| + } |
| + |
| + return reloc; |
| +} |
| + |
| +int |
| +riscv_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 (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 (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_RISCV_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 ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED, |
| + fragS *fragp) |
| +{ |
| + gas_assert (RELAX_BRANCH_P (fragp->fr_subtype)); |
| + md_convert_frag_branch (fragp); |
| +} |
| + |
| +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\ |
| +")); |
| +} |
| + |
| +/* Standard calling conventions leave the CFA at SP on entry. */ |
| +void |
| +riscv_cfi_frame_initial_instructions (void) |
| +{ |
| + cfi_add_CFA_def_cfa_register (X_SP); |
| +} |
| + |
| +int |
| +tc_riscv_regname_to_dw2regnum (char *regname) |
| +{ |
| + int reg; |
| + |
| + if ((reg = reg_lookup_internal (regname, RCLASS_GPR)) >= 0) |
| + return reg; |
| + |
| + if ((reg = reg_lookup_internal (regname, RCLASS_FPR)) >= 0) |
| + return reg + 32; |
| + |
| + as_bad (_("unknown register `%s'"), regname); |
| + return -1; |
| +} |
| + |
| +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)); |
| +} |
| + |
| +/* Pseudo-op table. */ |
| + |
| +static const pseudo_typeS riscv_pseudo_table[] = |
| +{ |
| + /* RISC-V-specific pseudo-ops. */ |
| + {"option", s_riscv_option, 0}, |
| + {"half", cons, 2}, |
| + {"word", cons, 4}, |
| + {"dword", cons, 8}, |
| + {"dtprelword", s_dtprel, 4}, |
| + {"dtpreldword", s_dtprel, 8}, |
| + {"bss", s_bss, 0}, |
| + {"align", s_align, 0}, |
| + |
| + /* leb128 doesn't work with relaxation; disallow it */ |
| + {"uleb128", s_err, 0}, |
| + {"sleb128", s_err, 0}, |
| + |
| + { NULL, NULL, 0 }, |
| +}; |
| + |
| +void |
| +riscv_pop_insert (void) |
| +{ |
| + extern void pop_insert (const pseudo_typeS *); |
| + |
| + pop_insert (riscv_pseudo_table); |
| +} |
| diff -urN original-binutils/gas/config/tc-riscv.h binutils/gas/config/tc-riscv.h |
| --- original-binutils/gas/config/tc-riscv.h 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/gas/config/tc-riscv.h 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,102 @@ |
| +/* tc-riscv.h -- header file for tc-riscv.c. |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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 LOCAL_LABELS_FB 1 |
| +#define FAKE_LABEL_NAME ".L0 " |
| + |
| +#define md_relax_frag(segment, fragp, stretch) \ |
| + riscv_relax_frag(segment, fragp, stretch) |
| +extern int riscv_relax_frag (asection *, struct frag *, long); |
| + |
| +#define md_section_align(seg,size) (size) |
| +#define md_undefined_symbol(name) (0) |
| +#define md_operand(x) |
| + |
| +#define MAX_MEM_FOR_RS_ALIGN_CODE (1 + 2) |
| + |
| +#define TC_SYMFIELD_TYPE int |
| + |
| +/* The ISA of the target may change based on command-line arguments. */ |
| +#define TARGET_FORMAT riscv_target_format() |
| +extern const char *riscv_target_format (void); |
| + |
| +#define md_after_parse_args() riscv_after_parse_args() |
| +extern void riscv_after_parse_args (void); |
| + |
| +#define tc_init_after_args() riscv_init_after_args() |
| +extern void riscv_init_after_args (void); |
| + |
| +#define md_parse_long_option(arg) riscv_parse_long_option (arg) |
| +extern int riscv_parse_long_option (const char *); |
| + |
| +/* 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) 1 |
| +#define TC_FORCE_RELOCATION_LOCAL(FIX) 1 |
| +#define DIFF_EXPR_OK 1 |
| + |
| +extern void riscv_pop_insert (void); |
| +#define md_pop_insert() riscv_pop_insert() |
| + |
| +#define TARGET_USE_CFIPOP 1 |
| + |
| +#define tc_cfi_frame_initial_instructions riscv_cfi_frame_initial_instructions |
| +extern void riscv_cfi_frame_initial_instructions (void); |
| + |
| +#define tc_regname_to_dw2regnum tc_riscv_regname_to_dw2regnum |
| +extern int tc_riscv_regname_to_dw2regnum (char *regname); |
| + |
| +extern bfd_boolean rv64; |
| +#define DWARF2_DEFAULT_RETURN_COLUMN X_RA |
| +#define DWARF2_CIE_DATA_ALIGNMENT (rv64 ? 8 : 4) |
| + |
| +#define elf_tc_final_processing riscv_elf_final_processing |
| +extern void riscv_elf_final_processing (void); |
| + |
| +#endif /* TC_RISCV */ |
| diff -urN original-binutils/gas/configure.tgt binutils/gas/configure.tgt |
| --- original-binutils/gas/configure.tgt 2014-10-14 09:32:03.000000000 +0200 |
| +++ binutils-2.25/gas/configure.tgt 2015-03-07 09:55:02.379135671 +0100 |
| @@ -86,6 +86,7 @@ |
| 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 ;; |
| rl78*) cpu_type=rl78 ;; |
| rx) cpu_type=rx ;; |
| @@ -384,6 +385,8 @@ |
| 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 -urN original-binutils/gas/Makefile.am binutils/gas/Makefile.am |
| --- original-binutils/gas/Makefile.am 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/gas/Makefile.am 2015-03-07 09:55:02.379135671 +0100 |
| @@ -171,6 +171,7 @@ |
| config/tc-pdp11.c \ |
| config/tc-pj.c \ |
| config/tc-ppc.c \ |
| + config/tc-riscv.c \ |
| config/tc-rl78.c \ |
| config/tc-rx.c \ |
| config/tc-s390.c \ |
| @@ -242,6 +243,7 @@ |
| config/tc-pdp11.h \ |
| config/tc-pj.h \ |
| config/tc-ppc.h \ |
| + config/tc-riscv.h \ |
| config/tc-rl78.h \ |
| config/tc-rx.h \ |
| config/tc-s390.h \ |
| diff -urN original-binutils/gas/Makefile.in binutils/gas/Makefile.in |
| --- original-binutils/gas/Makefile.in 2014-10-14 09:32:02.000000000 +0200 |
| +++ binutils-2.25/gas/Makefile.in 2015-03-07 09:55:02.379135671 +0100 |
| @@ -440,6 +440,7 @@ |
| config/tc-pdp11.c \ |
| config/tc-pj.c \ |
| config/tc-ppc.c \ |
| + config/tc-riscv.c \ |
| config/tc-rl78.c \ |
| config/tc-rx.c \ |
| config/tc-s390.c \ |
| @@ -511,6 +512,7 @@ |
| config/tc-pdp11.h \ |
| config/tc-pj.h \ |
| config/tc-ppc.h \ |
| + config/tc-riscv.h \ |
| config/tc-rl78.h \ |
| config/tc-rx.h \ |
| config/tc-s390.h \ |
| @@ -866,6 +868,7 @@ |
| @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-rl78.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@ |
| @@ -1571,6 +1574,20 @@ |
| @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-rl78.o: config/tc-rl78.c |
| @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rl78.o -MD -MP -MF $(DEPDIR)/tc-rl78.Tpo -c -o tc-rl78.o `test -f 'config/tc-rl78.c' || echo '$(srcdir)/'`config/tc-rl78.c |
| @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tc-rl78.Tpo $(DEPDIR)/tc-rl78.Po |
| diff -urN original-binutils/include/dis-asm.h binutils/include/dis-asm.h |
| --- original-binutils/include/dis-asm.h 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/include/dis-asm.h 2015-03-07 09:55:02.379135671 +0100 |
| @@ -254,6 +254,7 @@ |
| extern int print_insn_little_mips (bfd_vma, disassemble_info *); |
| extern int print_insn_little_nios2 (bfd_vma, disassemble_info *); |
| extern int print_insn_little_powerpc (bfd_vma, disassemble_info *); |
| +extern int print_insn_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 *); |
| @@ -313,6 +314,7 @@ |
| extern void print_i386_disassembler_options (FILE *); |
| extern void print_mips_disassembler_options (FILE *); |
| extern void print_ppc_disassembler_options (FILE *); |
| +extern void print_riscv_disassembler_options (FILE *); |
| extern void print_arm_disassembler_options (FILE *); |
| extern void parse_arm_disassembler_option (char *); |
| extern void print_s390_disassembler_options (FILE *); |
| diff -urN original-binutils/include/elf/common.h binutils/include/elf/common.h |
| --- original-binutils/include/elf/common.h 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/include/elf/common.h 2015-03-07 09:55:02.383135671 +0100 |
| @@ -301,6 +301,7 @@ |
| #define EM_INTEL207 207 /* Reserved by Intel */ |
| #define EM_INTEL208 208 /* Reserved by Intel */ |
| #define EM_INTEL209 209 /* Reserved by Intel */ |
| +#define EM_RISCV 243 /* Reserved by Intel */ |
| |
| /* 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 -urN original-binutils/include/elf/riscv.h binutils/include/elf/riscv.h |
| --- original-binutils/include/elf/riscv.h 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/include/elf/riscv.h 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,138 @@ |
| +/* RISC-V ELF support for BFD. |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrw Waterman <waterman@cs.berkeley.edu> at UC Berkeley. |
| + 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) |
| + /* Relocation types used by the dynamic linker. */ |
| + RELOC_NUMBER (R_RISCV_NONE, 0) |
| + RELOC_NUMBER (R_RISCV_32, 1) |
| + RELOC_NUMBER (R_RISCV_64, 2) |
| + RELOC_NUMBER (R_RISCV_RELATIVE, 3) |
| + RELOC_NUMBER (R_RISCV_COPY, 4) |
| + RELOC_NUMBER (R_RISCV_JUMP_SLOT, 5) |
| + RELOC_NUMBER (R_RISCV_TLS_DTPMOD32, 6) |
| + RELOC_NUMBER (R_RISCV_TLS_DTPMOD64, 7) |
| + RELOC_NUMBER (R_RISCV_TLS_DTPREL32, 8) |
| + RELOC_NUMBER (R_RISCV_TLS_DTPREL64, 9) |
| + RELOC_NUMBER (R_RISCV_TLS_TPREL32, 10) |
| + RELOC_NUMBER (R_RISCV_TLS_TPREL64, 11) |
| + |
| + /* Relocation types not used by the dynamic linker. */ |
| + RELOC_NUMBER (R_RISCV_BRANCH, 16) |
| + RELOC_NUMBER (R_RISCV_JAL, 17) |
| + RELOC_NUMBER (R_RISCV_CALL, 18) |
| + RELOC_NUMBER (R_RISCV_CALL_PLT, 19) |
| + RELOC_NUMBER (R_RISCV_GOT_HI20, 20) |
| + RELOC_NUMBER (R_RISCV_TLS_GOT_HI20, 21) |
| + RELOC_NUMBER (R_RISCV_TLS_GD_HI20, 22) |
| + RELOC_NUMBER (R_RISCV_PCREL_HI20, 23) |
| + RELOC_NUMBER (R_RISCV_PCREL_LO12_I, 24) |
| + RELOC_NUMBER (R_RISCV_PCREL_LO12_S, 25) |
| + RELOC_NUMBER (R_RISCV_HI20, 26) |
| + RELOC_NUMBER (R_RISCV_LO12_I, 27) |
| + RELOC_NUMBER (R_RISCV_LO12_S, 28) |
| + RELOC_NUMBER (R_RISCV_TPREL_HI20, 29) |
| + RELOC_NUMBER (R_RISCV_TPREL_LO12_I, 30) |
| + RELOC_NUMBER (R_RISCV_TPREL_LO12_S, 31) |
| + RELOC_NUMBER (R_RISCV_TPREL_ADD, 32) |
| + RELOC_NUMBER (R_RISCV_ADD8, 33) |
| + RELOC_NUMBER (R_RISCV_ADD16, 34) |
| + RELOC_NUMBER (R_RISCV_ADD32, 35) |
| + RELOC_NUMBER (R_RISCV_ADD64, 36) |
| + RELOC_NUMBER (R_RISCV_SUB8, 37) |
| + RELOC_NUMBER (R_RISCV_SUB16, 38) |
| + RELOC_NUMBER (R_RISCV_SUB32, 39) |
| + RELOC_NUMBER (R_RISCV_SUB64, 40) |
| + RELOC_NUMBER (R_RISCV_GNU_VTINHERIT, 41) |
| + RELOC_NUMBER (R_RISCV_GNU_VTENTRY, 42) |
| + RELOC_NUMBER (R_RISCV_ALIGN, 43) |
| +END_RELOC_NUMBERS (R_RISCV_max) |
| + |
| +/* 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; |
| +} |
| + |
| +#endif /* _ELF_RISCV_H */ |
| diff -urN original-binutils/include/opcode/riscv.h binutils/include/opcode/riscv.h |
| --- original-binutils/include/opcode/riscv.h 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/include/opcode/riscv.h 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,320 @@ |
| +/* 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_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) << 12) | (RV_IMM_SIGN(x) << 32)) |
| +#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, 12, 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_PCREL_HIGH_PART(VALUE, PC) RISCV_CONST_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 X_RA 1 |
| +#define X_SP 2 |
| +#define X_GP 3 |
| +#define X_TP 4 |
| +#define X_T0 5 |
| +#define X_T1 6 |
| +#define X_T2 7 |
| +#define X_T3 28 |
| + |
| +#define NGPR 32 |
| +#define NFPR 32 |
| +#define NVGPR 32 |
| +#define NVFPR 32 |
| + |
| +#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 |
| + |
| +/* 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_J, |
| + M_LI, |
| + M_VF, |
| + M_NUM_MACROS |
| +}; |
| + |
| + |
| +extern const char * const riscv_gpr_names_numeric[NGPR]; |
| +extern const char * const riscv_gpr_names_abi[NGPR]; |
| +extern const char * const riscv_fpr_names_numeric[NFPR]; |
| +extern const char * const riscv_fpr_names_abi[NFPR]; |
| +extern const char * const riscv_vec_gpr_names[NVGPR]; |
| +extern const char * const riscv_vec_fpr_names[NVFPR]; |
| + |
| +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 /* _RISCV_H_ */ |
| diff -urN original-binutils/include/opcode/riscv-opc.h binutils/include/opcode/riscv-opc.h |
| --- original-binutils/include/opcode/riscv-opc.h 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/include/opcode/riscv-opc.h 2015-03-07 09:51:45.659139025 +0100 |
| @@ -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 -urN original-binutils/ld/configure.tgt binutils/ld/configure.tgt |
| --- original-binutils/ld/configure.tgt 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/ld/configure.tgt 2015-03-07 09:55:02.383135671 +0100 |
| @@ -604,6 +604,12 @@ |
| powerpc-*-beos*) targ_emul=aixppc ;; |
| powerpc-*-windiss*) targ_emul=elf32ppcwindiss ;; |
| powerpc-*-lynxos*) targ_emul=ppclynx ;; |
| +riscv32*-*-*) targ_emul=elf32lriscv |
| + targ_extra_emuls="elf64lriscv" |
| + targ_extra_libpath=$targ_extra_emuls ;; |
| +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 -urN original-binutils/ld/emulparams/elf32lriscv-defs.sh binutils/ld/emulparams/elf32lriscv-defs.sh |
| --- original-binutils/ld/emulparams/elf32lriscv-defs.sh 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/ld/emulparams/elf32lriscv-defs.sh 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,39 @@ |
| +# This is an ELF platform. |
| +SCRIPT_NAME=elf |
| +ARCH=riscv |
| +OUTPUT_FORMAT="elf32-littleriscv" |
| +NO_REL_RELOCS=yes |
| + |
| +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=0x800000 |
| +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" |
| +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" |
| + |
| +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 |
| diff -urN original-binutils/ld/emulparams/elf32lriscv.sh binutils/ld/emulparams/elf32lriscv.sh |
| --- original-binutils/ld/emulparams/elf32lriscv.sh 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/ld/emulparams/elf32lriscv.sh 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,2 @@ |
| +. ${srcdir}/emulparams/elf32lriscv-defs.sh |
| +OUTPUT_FORMAT="elf32-littleriscv" |
| diff -urN original-binutils/ld/emulparams/elf64lriscv-defs.sh binutils/ld/emulparams/elf64lriscv-defs.sh |
| --- original-binutils/ld/emulparams/elf64lriscv-defs.sh 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/ld/emulparams/elf64lriscv-defs.sh 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1 @@ |
| +. ${srcdir}/emulparams/elf32lriscv-defs.sh |
| diff -urN original-binutils/ld/emulparams/elf64lriscv.sh binutils/ld/emulparams/elf64lriscv.sh |
| --- original-binutils/ld/emulparams/elf64lriscv.sh 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/ld/emulparams/elf64lriscv.sh 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,2 @@ |
| +. ${srcdir}/emulparams/elf64lriscv-defs.sh |
| +OUTPUT_FORMAT="elf64-littleriscv" |
| diff -urN original-binutils/ld/emultempl/riscvelf.em binutils/ld/emultempl/riscvelf.em |
| --- original-binutils/ld/emultempl/riscvelf.em 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/ld/emultempl/riscvelf.em 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,68 @@ |
| +# 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" |
| + |
| +static void |
| +riscv_elf_before_allocation (void) |
| +{ |
| + gld${EMULATION_NAME}_before_allocation (); |
| + |
| + if (link_info.discard == discard_sec_merge) |
| + link_info.discard = discard_l; |
| + |
| + /* We always need at least some relaxation to handle code alignment. */ |
| + if (RELAXATION_DISABLED_BY_USER) |
| + TARGET_ENABLE_RELAXATION; |
| + else |
| + ENABLE_RELAXATION; |
| + |
| + link_info.relax_pass = 2; |
| +} |
| + |
| +static void |
| +gld${EMULATION_NAME}_after_allocation (void) |
| +{ |
| + int need_layout = 0; |
| + |
| + /* Don't attempt to discard unused .eh_frame sections until the final link, |
| + as we can't reliably tell if they're used until after relaxation. */ |
| + if (!link_info.relocatable) |
| + { |
| + need_layout = bfd_elf_discard_info (link_info.output_bfd, &link_info); |
| + if (need_layout < 0) |
| + { |
| + einfo ("%X%P: .eh_frame/.stab edit: %E\n"); |
| + return; |
| + } |
| + } |
| + |
| + gld${EMULATION_NAME}_map_segments (need_layout); |
| +} |
| + |
| +EOF |
| + |
| +LDEMUL_BEFORE_ALLOCATION=riscv_elf_before_allocation |
| +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation |
| diff -urN original-binutils/ld/Makefile.am binutils/ld/Makefile.am |
| --- original-binutils/ld/Makefile.am 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/ld/Makefile.am 2015-03-07 09:55:02.383135671 +0100 |
| @@ -258,6 +258,7 @@ |
| eelf32ppcsim.c \ |
| eelf32ppcvxworks.c \ |
| eelf32ppcwindiss.c \ |
| + eelf32lriscv.c \ |
| eelf32rl78.c \ |
| eelf32rx.c \ |
| eelf32tilegx.c \ |
| @@ -464,6 +465,7 @@ |
| eelf64btsmip_fbsd.c \ |
| eelf64hppa.c \ |
| eelf64lppc.c \ |
| + eelf64lriscv.c \ |
| eelf64ltsmip.c \ |
| eelf64ltsmip_fbsd.c \ |
| eelf64mmix.c \ |
| @@ -1104,6 +1106,11 @@ |
| ldemul-list.h \ |
| $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} |
| |
| +eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \ |
| + $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ |
| + $(srcdir)/emultempl/riscvelf.em $(srcdir)/scripttempl/elf.sc \ |
| + ${GEN_DEPENDS} |
| + |
| eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \ |
| $(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \ |
| $(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \ |
| @@ -1861,6 +1868,12 @@ |
| ldemul-list.h \ |
| $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} |
| |
| +eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \ |
| + $(srcdir)/emulparams/elf64lriscv-defs.sh \ |
| + $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ |
| + $(srcdir)/emultempl/riscvelf.em $(srcdir)/scripttempl/elf.sc \ |
| + ${GEN_DEPENDS} |
| + |
| eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \ |
| $(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \ |
| $(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \ |
| diff -urN original-binutils/ld/Makefile.in binutils/ld/Makefile.in |
| --- original-binutils/ld/Makefile.in 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/ld/Makefile.in 2015-03-07 09:55:02.383135671 +0100 |
| @@ -546,6 +546,7 @@ |
| eelf32lppclinux.c \ |
| eelf32lppcnto.c \ |
| eelf32lppcsim.c \ |
| + eelf32lriscv.c \ |
| eelf32m32c.c \ |
| eelf32mb_linux.c \ |
| eelf32mbel_linux.c \ |
| @@ -771,6 +772,7 @@ |
| eelf64btsmip_fbsd.c \ |
| eelf64hppa.c \ |
| eelf64lppc.c \ |
| + eelf64lriscv.c \ |
| eelf64ltsmip.c \ |
| eelf64ltsmip_fbsd.c \ |
| eelf64mmix.c \ |
| @@ -1157,6 +1159,7 @@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppclinux.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)/eelf32lr5900.Po@am__quote@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lr5900n32.Po@am__quote@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lsmip.Po@am__quote@ |
| @@ -1211,6 +1214,7 @@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip_fbsd.Po@am__quote@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Po@am__quote@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/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)/eelf64ltsmip_fbsd.Po@am__quote@ |
| @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64mmix.Po@am__quote@ |
| @@ -2545,6 +2549,11 @@ |
| ldemul-list.h \ |
| $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} |
| |
| +eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \ |
| + $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ |
| + $(srcdir)/emultempl/riscvelf.em $(srcdir)/scripttempl/elf.sc \ |
| + ${GEN_DEPENDS} |
| + |
| eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \ |
| $(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \ |
| $(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \ |
| @@ -3302,6 +3311,12 @@ |
| ldemul-list.h \ |
| $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} |
| |
| +eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \ |
| + $(srcdir)/emulparams/elf64lriscv-defs.sh \ |
| + $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ |
| + $(srcdir)/emultempl/riscvelf.em $(srcdir)/scripttempl/elf.sc \ |
| + ${GEN_DEPENDS} |
| + |
| eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \ |
| $(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \ |
| $(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \ |
| diff -urN original-binutils/opcodes/configure binutils/opcodes/configure |
| --- original-binutils/opcodes/configure 2014-12-23 15:22:07.000000000 +0100 |
| +++ binutils-2.25/opcodes/configure 2015-03-07 09:55:02.387135671 +0100 |
| @@ -12590,6 +12590,7 @@ |
| 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_rl78_arch) ta="$ta rl78-dis.lo rl78-decode.lo";; |
| diff -urN original-binutils/opcodes/disassemble.c binutils/opcodes/disassemble.c |
| --- original-binutils/opcodes/disassemble.c 2014-10-14 09:32:04.000000000 +0200 |
| +++ binutils-2.25/opcodes/disassemble.c 2015-03-07 09:55:02.391135671 +0100 |
| @@ -373,6 +373,11 @@ |
| disassemble = print_insn_little_powerpc; |
| break; |
| #endif |
| +#ifdef ARCH_riscv |
| + case bfd_arch_riscv: |
| + disassemble = print_insn_riscv; |
| + break; |
| +#endif |
| #ifdef ARCH_rs6000 |
| case bfd_arch_rs6000: |
| if (bfd_get_mach (abfd) == bfd_mach_ppc_620) |
| @@ -545,6 +550,9 @@ |
| #ifdef ARCH_powerpc |
| print_ppc_disassembler_options (stream); |
| #endif |
| +#ifdef ARCH_riscv |
| + print_riscv_disassembler_options (stream); |
| +#endif |
| #ifdef ARCH_i386 |
| print_i386_disassembler_options (stream); |
| #endif |
| diff -urN original-binutils/opcodes/riscv-dis.c binutils/opcodes/riscv-dis.c |
| --- original-binutils/opcodes/riscv-dis.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/opcodes/riscv-dis.c 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,492 @@ |
| +/* RISC-V disassembler |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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> |
| + |
| +struct riscv_private_data |
| +{ |
| + bfd_vma gp; |
| + bfd_vma print_addr; |
| + bfd_vma hi_addr[OP_MASK_RD + 1]; |
| +}; |
| + |
| +static const char * const *riscv_gpr_names; |
| +static const char * const *riscv_fpr_names; |
| + |
| +/* Other options */ |
| +static int no_aliases; /* If set disassemble as most general inst. */ |
| + |
| +static void |
| +set_default_riscv_dis_options (void) |
| +{ |
| + riscv_gpr_names = riscv_gpr_names_abi; |
| + riscv_fpr_names = riscv_fpr_names_abi; |
| + no_aliases = 0; |
| +} |
| + |
| +static void |
| +parse_riscv_dis_option (const char *option) |
| +{ |
| + if (CONST_STRNEQ (option, "no-aliases")) |
| + no_aliases = 1; |
| + else if (CONST_STRNEQ (option, "numeric")) |
| + { |
| + riscv_gpr_names = riscv_gpr_names_numeric; |
| + riscv_fpr_names = riscv_fpr_names_numeric; |
| + } |
| + |
| + /* Invalid option. */ |
| + fprintf (stderr, _("Unrecognized disassembler option: %s\n"), option); |
| +} |
| + |
| +static void |
| +parse_riscv_dis_options (const char *opts_in) |
| +{ |
| + char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts; |
| + |
| + set_default_riscv_dis_options (); |
| + |
| + for ( ; opt_end != NULL; opt = opt_end + 1) |
| + { |
| + if ((opt_end = strchr (opt, ',')) != NULL) |
| + *opt_end = 0; |
| + parse_riscv_dis_option (opt); |
| + } |
| + |
| + free (opts); |
| +} |
| + |
| +/* 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 == X_GP && pd->gp != (bfd_vma)-1) |
| + pd->print_addr = pd->gp + offset; |
| + else if (base_reg == X_TP) |
| + 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", (int)((l >> OP_SH_RS2) & OP_MASK_RS2)); |
| + break; |
| + case 'j': |
| + (*info->fprintf_func) |
| + ( info->stream, "%d", (int)((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM)); |
| + break; |
| + } |
| + break; |
| + |
| + /* Xhwacha */ |
| + case '#': |
| + switch ( *++d ) { |
| + case 'g': |
| + (*info->fprintf_func) |
| + ( info->stream, "%d", |
| + (int)((l >> OP_SH_IMMNGPR) & OP_MASK_IMMNGPR)); |
| + break; |
| + case 'f': |
| + (*info->fprintf_func) |
| + ( info->stream, "%d", |
| + (int)((l >> OP_SH_IMMNFPR) & OP_MASK_IMMNFPR)); |
| + break; |
| + case 'p': |
| + (*info->fprintf_func) |
| + ( info->stream, "%d", |
| + (int)((l >> OP_SH_CUSTOM_IMM) & OP_MASK_CUSTOM_IMM)); |
| + break; |
| + case 'n': |
| + (*info->fprintf_func) |
| + ( info->stream, "%d", |
| + (int)(((l >> OP_SH_IMMSEGNELM) & OP_MASK_IMMSEGNELM) + 1)); |
| + break; |
| + case 'd': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_gpr_names[(l >> OP_SH_VRD) & OP_MASK_VRD]); |
| + break; |
| + case 's': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_gpr_names[(l >> OP_SH_VRS) & OP_MASK_VRS]); |
| + break; |
| + case 't': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_gpr_names[(l >> OP_SH_VRT) & OP_MASK_VRT]); |
| + break; |
| + case 'r': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_gpr_names[(l >> OP_SH_VRR) & OP_MASK_VRR]); |
| + break; |
| + case 'D': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_fpr_names[(l >> OP_SH_VFD) & OP_MASK_VFD]); |
| + break; |
| + case 'S': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_fpr_names[(l >> OP_SH_VFS) & OP_MASK_VFS]); |
| + break; |
| + case 'T': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_fpr_names[(l >> OP_SH_VFT) & OP_MASK_VFT]); |
| + break; |
| + case 'R': |
| + (*info->fprintf_func) |
| + ( info->stream, "%s", |
| + riscv_vec_fpr_names[(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", riscv_gpr_names[rs1]); |
| + break; |
| + |
| + case 't': |
| + (*info->fprintf_func) (info->stream, "%s", |
| + riscv_gpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]); |
| + break; |
| + |
| + case 'u': |
| + (*info->fprintf_func) (info->stream, "0x%x", (unsigned)EXTRACT_UTYPE_IMM (l) >> 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 || (l & MASK_JALR) == MATCH_JALR) |
| + maybe_print_address (pd, rs1, EXTRACT_ITYPE_IMM (l)); |
| + (*info->fprintf_func) (info->stream, "%d", (int)EXTRACT_ITYPE_IMM (l)); |
| + break; |
| + |
| + case 'q': |
| + maybe_print_address (pd, rs1, EXTRACT_STYPE_IMM (l)); |
| + (*info->fprintf_func) (info->stream, "%d", (int)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); |
| + else if ((l & MASK_LUI) == MATCH_LUI) |
| + pd->hi_addr[rd] = EXTRACT_UTYPE_IMM (l); |
| + (*info->fprintf_func) (info->stream, "%s", riscv_gpr_names[rd]); |
| + break; |
| + |
| + case 'z': |
| + (*info->fprintf_func) (info->stream, "%s", riscv_gpr_names[0]); |
| + break; |
| + |
| + case '>': |
| + (*info->fprintf_func) (info->stream, "0x%x", |
| + (unsigned)((l >> OP_SH_SHAMT) & OP_MASK_SHAMT)); |
| + break; |
| + |
| + case '<': |
| + (*info->fprintf_func) (info->stream, "0x%x", |
| + (unsigned)((l >> OP_SH_SHAMTW) & OP_MASK_SHAMTW)); |
| + break; |
| + |
| + case 'S': |
| + case 'U': |
| + (*info->fprintf_func) (info->stream, "%s", riscv_fpr_names[rs1]); |
| + break; |
| + |
| + case 'T': |
| + (*info->fprintf_func) (info->stream, "%s", |
| + riscv_fpr_names[(l >> OP_SH_RS2) & OP_MASK_RS2]); |
| + break; |
| + |
| + case 'D': |
| + (*info->fprintf_func) (info->stream, "%s", riscv_fpr_names[rd]); |
| + break; |
| + |
| + case 'R': |
| + (*info->fprintf_func) (info->stream, "%s", |
| + riscv_fpr_names[(l >> OP_SH_RS3) & OP_MASK_RS3]); |
| + break; |
| + |
| + case 'E': |
| + { |
| + const char* csr_name = NULL; |
| + unsigned int csr = (l >> OP_SH_CSR) & OP_MASK_CSR; |
| + switch (csr) |
| + { |
| + #define DECLARE_CSR(name, num) case num: csr_name = #name; break; |
| + #include "opcode/riscv-opc.h" |
| + #undef DECLARE_CSR |
| + } |
| + if (csr_name) |
| + (*info->fprintf_func) (info->stream, "%s", csr_name); |
| + else |
| + (*info->fprintf_func) (info->stream, "0x%x", csr); |
| + 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; |
| + } |
| + } |
| +} |
| + |
| +/* Print the RISC-V 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 |
| +riscv_disassemble_insn (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 *riscv_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)) |
| + { |
| + riscv_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); |
| + |
| + 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 = riscv_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, " # "); |
| + (*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; |
| +} |
| + |
| +int |
| +print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info) |
| +{ |
| + uint16_t i2; |
| + insn_t insn = 0; |
| + bfd_vma n; |
| + int status; |
| + |
| + if (info->disassembler_options != NULL) |
| + { |
| + parse_riscv_dis_options (info->disassembler_options); |
| + /* Avoid repeatedly parsing the options. */ |
| + info->disassembler_options = NULL; |
| + } |
| + else if (riscv_gpr_names == NULL) |
| + set_default_riscv_dis_options (); |
| + |
| + /* Instructions are a sequence of 2-byte packets in little-endian order. */ |
| + 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 = bfd_getl16 (&i2); |
| + insn |= (insn_t)i2 << (8*n); |
| + } |
| + |
| + return riscv_disassemble_insn (memaddr, insn, info); |
| +} |
| + |
| +void |
| +print_riscv_disassembler_options (FILE *stream) |
| +{ |
| + fprintf (stream, _("\n\ |
| +The following RISC-V-specific disassembler options are supported for use\n\ |
| +with the -M switch (multiple options should be separated by commas):\n")); |
| + |
| + fprintf (stream, _("\n\ |
| + numeric Print numeric reigster names, rather than ABI names.\n")); |
| + |
| + fprintf (stream, _("\n\ |
| + no-aliases Disassemble only into canonical instructions, rather\n\ |
| + than into pseudoinstructions.\n")); |
| + |
| + fprintf (stream, _("\n")); |
| +} |
| diff -urN original-binutils/opcodes/riscv-opc.c binutils/opcodes/riscv-opc.c |
| --- original-binutils/opcodes/riscv-opc.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ binutils-2.25/opcodes/riscv-opc.c 2015-03-07 09:51:45.659139025 +0100 |
| @@ -0,0 +1,729 @@ |
| +/* RISC-V opcode list |
| + Copyright 2011-2014 Free Software Foundation, Inc. |
| + |
| + Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley. |
| + Based on MIPS target. |
| + |
| + 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 "sysdep.h" |
| +#include "opcode/riscv.h" |
| +#include <stdio.h> |
| + |
| +/* Register names used by gas and objdump. */ |
| + |
| +const char * const riscv_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" |
| +}; |
| + |
| +const char * const riscv_gpr_names_abi[32] = { |
| + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", |
| + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", |
| + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", |
| + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" |
| +}; |
| + |
| +const char * const riscv_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" |
| +}; |
| + |
| +const char * const riscv_fpr_names_abi[32] = { |
| + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", |
| + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", |
| + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", |
| + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" |
| +}; |
| + |
| +const char * const riscv_vec_gpr_names[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" |
| +}; |
| + |
| +const char * const riscv_vec_fpr_names[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" |
| +}; |
| + |
| +/* 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 }, |
| +{"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 | (X_RA << 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 | (X_RA << 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", (X_T0 << OP_SH_RS1) | (X_RA << OP_SH_RD), (int) M_CALL, match_never, INSN_MACRO }, |
| +{"tail", "I", "c", (X_T0 << OP_SH_RS1), (int) M_CALL, match_never, INSN_MACRO }, |
| +{"jump", "I", "c,s", 0, (int) M_CALL, 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 | (X_RA << OP_SH_RD), MASK_JALR | MASK_RD | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 }, |
| +{"jalr", "I", "s,j", MATCH_JALR | (X_RA << 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 |