(root)/
binutils-2.41/
bfd/
cpu-riscv.c
       1  /* BFD backend for RISC-V
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3  
       4     Contributed by Andrew Waterman (andrew@sifive.com).
       5     Based on MIPS target.
       6  
       7     This file is part of BFD, the Binary File Descriptor library.
       8  
       9     This program is free software; you can redistribute it and/or modify
      10     it under the terms of the GNU General Public License as published by
      11     the Free Software Foundation; either version 3 of the License, or
      12     (at your option) any later version.
      13  
      14     This program is distributed in the hope that it will be useful,
      15     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17     GNU General Public License for more details.
      18  
      19     You should have received a copy of the GNU General Public License
      20     along with this program; see the file COPYING3. If not,
      21     see <http://www.gnu.org/licenses/>.  */
      22  
      23  #include "sysdep.h"
      24  #include "bfd.h"
      25  #include "libbfd.h"
      26  #include "cpu-riscv.h"
      27  
      28  static const bfd_arch_info_type *
      29  riscv_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b)
      30  {
      31    if (a->arch != b->arch)
      32      return NULL;
      33  
      34    /* Machine compatibility is checked in
      35       _bfd_riscv_elf_merge_private_bfd_data.  */
      36  
      37    return a;
      38  }
      39  
      40  /* Return TRUE if STRING matches the architecture described by INFO.  */
      41  
      42  static bool
      43  riscv_scan (const struct bfd_arch_info *info, const char *string)
      44  {
      45    if (bfd_default_scan (info, string))
      46      return true;
      47  
      48    /* The incoming STRING might take the form of riscv:rvXXzzz, where XX is
      49       32 or 64, and zzz are one or more extension characters.  As we
      50       currently only have 3 architectures defined, 'riscv', 'riscv:rv32',
      51       and 'riscv:rv64', we would like to ignore the zzz for the purpose of
      52       matching here.
      53  
      54       However, we don't want the default 'riscv' to match over a more
      55       specific 'riscv:rv32' or 'riscv:rv64', so in the case of the default
      56       architecture (with the shorter 'riscv' name) we don't allow any
      57       special matching, but for the 'riscv:rvXX' cases, we allow a match
      58       with any additional trailing characters being ignored.  */
      59    if (!info->the_default
      60        && strncasecmp (string, info->printable_name,
      61                        strlen (info->printable_name)) == 0)
      62      return true;
      63  
      64    return false;
      65  }
      66  
      67  #define N(BITS, NUMBER, PRINT, DEFAULT, NEXT)			\
      68    {								\
      69      BITS,      /* Bits in a word.  */				\
      70      BITS,      /* Bits in an address.  */			\
      71      8,	       /* Bits in a byte.  */				\
      72      bfd_arch_riscv,						\
      73      NUMBER,							\
      74      "riscv",							\
      75      PRINT,							\
      76      3,								\
      77      DEFAULT,							\
      78      riscv_compatible,						\
      79      riscv_scan,							\
      80      bfd_arch_default_fill,					\
      81      NEXT,							\
      82      0 /* Maximum offset of a reloc from the start of an insn.  */\
      83    }
      84  
      85  /* This enum must be kept in the same order as arch_info_struct.  */
      86  enum
      87  {
      88    I_riscv64,
      89    I_riscv32
      90  };
      91  
      92  #define NN(index) (&arch_info_struct[(index) + 1])
      93  
      94  /* This array must be kept in the same order as the anonymous enum above,
      95     and each entry except the last should end with NN (my enum value).  */
      96  static const bfd_arch_info_type arch_info_struct[] =
      97  {
      98    N (64, bfd_mach_riscv64, "riscv:rv64", false, NN (I_riscv64)),
      99    N (32, bfd_mach_riscv32, "riscv:rv32", false, NULL)
     100  };
     101  
     102  /* The default architecture is riscv:rv64.  */
     103  const bfd_arch_info_type bfd_riscv_arch =
     104    N (64, 0, "riscv", true, &arch_info_struct[0]);
     105  
     106  /* List for all supported ISA spec versions.  */
     107  const struct riscv_spec riscv_isa_specs[] =
     108  {
     109    {"2.2",      ISA_SPEC_CLASS_2P2},
     110    {"20190608", ISA_SPEC_CLASS_20190608},
     111    {"20191213", ISA_SPEC_CLASS_20191213},
     112  };
     113  
     114  /* List for all supported privileged spec versions.  */
     115  const struct riscv_spec riscv_priv_specs[] =
     116  {
     117    {"1.9.1", PRIV_SPEC_CLASS_1P9P1},
     118    {"1.10",  PRIV_SPEC_CLASS_1P10},
     119    {"1.11",  PRIV_SPEC_CLASS_1P11},
     120    {"1.12",  PRIV_SPEC_CLASS_1P12},
     121  };
     122  
     123  /* Get the corresponding CSR version class by giving privilege
     124     version numbers.  It is usually used to convert the priv
     125     attribute numbers into the corresponding class.  */
     126  
     127  void
     128  riscv_get_priv_spec_class_from_numbers (unsigned int major,
     129  					unsigned int minor,
     130  					unsigned int revision,
     131  					enum riscv_spec_class *class)
     132  {
     133    enum riscv_spec_class class_t = *class;
     134    char buf[36];
     135  
     136    if (revision != 0)
     137      snprintf (buf, sizeof (buf), "%u.%u.%u", major, minor, revision);
     138    else
     139      snprintf (buf, sizeof (buf), "%u.%u", major, minor);
     140  
     141    RISCV_GET_PRIV_SPEC_CLASS (buf, class_t);
     142    *class = class_t;
     143  }
     144  
     145  /* Define mapping symbols for riscv.  */
     146  
     147  bool
     148  riscv_elf_is_mapping_symbols (const char *name)
     149  {
     150    return (!strncmp (name, "$d", 2)
     151  	  || !strncmp (name, "$x", 2));
     152  }