[PATCH v1]RISC-V: Zcmt relaxationi support.

Jiawei jiawei@iscas.ac.cn
Thu Nov 27 02:53:32 GMT 2025
LGTM, thanks for you pick up this.


BR,

Jiawei

> This patch is refactored the 
> https://sourceware.org/pipermail/binutils/2024-January/131573.html.
>
> and below changes are made like
> a)Enabled zcmt relaxation from linker along --relax option.
> b)Added min-zcmt-size option to zcmt size heuristic.
> c)Disassembler support for zcmt insn.
> ---
>  bfd/elfnn-riscv.c                          | 648 ++++++++++++++++++++-
>  bfd/elfxx-riscv.c                          |  17 +
>  gas/config/tc-riscv.c                      |  41 +-
>  include/bfdlink.h                          |   3 +
>  include/elf/riscv.h                        |  10 +
>  ld/ldlex.h                                 |   1 +
>  ld/ldmain.c                                |   2 +
>  ld/lexsup.c                                |  13 +
>  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |   1 +
>  ld/testsuite/ld-riscv-elf/zcmt_relax.d     |  18 +
>  ld/testsuite/ld-riscv-elf/zcmt_relax.ld    |  38 ++
>  ld/testsuite/ld-riscv-elf/zcmt_relax.s     |   9 +
>  opcodes/riscv-dis.c                        |  40 ++
>  13 files changed, 831 insertions(+), 10 deletions(-)
>  create mode 100644 ld/testsuite/ld-riscv-elf/zcmt_relax.d
>  create mode 100644 ld/testsuite/ld-riscv-elf/zcmt_relax.ld
>  create mode 100644 ld/testsuite/ld-riscv-elf/zcmt_relax.s
>
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index dd5268b7d16..d5642842527 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -208,6 +208,40 @@ elfNN_riscv_mkobject (bfd *abfd)
>  #include "elf/common.h"
>  #include "elf/internal.h"
>
> +/* debug use */
> +#define ZCMT_PRINT_TABLE_JUMP_ENTRIES 0
> +
> +/* Hash table for storing table jump candidate entries.  */
> +typedef struct
> +{
> +  htab_t tbljt_htab;
> +  htab_t tbljalt_htab;
> +  uintNN_t *tbj_indexes;
> +  asection *tablejump_sec;
> +  bfd *tablejump_sec_owner;
> +  /* cmjt table active index */
> +  short tbljt_index;
> +  /* cmjalt table active index */
> +  short tbljalt_index;
> +  /* used for profiling */
> +  int end_idx;
> +  int total_saving;
> +
> +  /* debug use.  */
> +  int *savings;
> +  const char **names;
> +} riscv_table_jump_htab_t;
> +
> +typedef struct
> +{
> +  bfd_vma address;
> +  unsigned int index;
> +
> +  /* debug use.  */
> +  const char *name;
> +  int benefit;
> +} riscv_table_jump_htab_entry;
> +
>  struct riscv_elf_link_hash_table
>  {
>    struct elf_link_hash_table elf;
> @@ -246,6 +280,7 @@ struct riscv_elf_link_hash_table
>    bool (*make_plt_header) (bfd *output_bfd, struct 
> riscv_elf_link_hash_table *htab);
>    bool (*make_plt_entry) (bfd *output_bfd, asection *got, bfd_vma 
> got_offset,
>                asection *plt, bfd_vma plt_offset);
> +   riscv_table_jump_htab_t *table_jump_htab;
>  };
>
>  /* Instruction access functions. */
> @@ -568,6 +603,83 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
>    return entry;
>  }
>
> +static hashval_t
> +riscv_table_jump_htab_hash (const void *entry)
> +{
> +  const riscv_table_jump_htab_entry *e = entry;
> +  return (hashval_t)(e->address >> 2);
> +}
> +
> +static int
> +riscv_table_jump_htab_entry_eq (const void *entry1, const void *entry2)
> +{
> +  const riscv_table_jump_htab_entry *e1 = entry1, *e2 = entry2;
> +  return e1->address == e2->address;
> +}
> +
> +static bool
> +riscv_init_table_jump_htab (riscv_table_jump_htab_t *htab)
> +{
> +  htab->names = bfd_zmalloc (sizeof (const char *) * 256);
> +  htab->savings = bfd_zmalloc (sizeof (unsigned int) * 256);
> +  htab->tbj_indexes = bfd_zmalloc (RISCV_ELF_WORD_BYTES * 256);
> +  htab->end_idx = 0;
> +  htab->total_saving = 0;
> +
> +  htab->tbljt_htab = htab_create (50, riscv_table_jump_htab_hash,
> +                  riscv_table_jump_htab_entry_eq, free);
> +  if (htab->tbljt_htab == NULL)
> +    return false;
> +
> +  htab->tbljalt_htab = htab_create (50, riscv_table_jump_htab_hash,
> +                  riscv_table_jump_htab_entry_eq, free);
> +  return htab->tbljalt_htab != NULL;
> +}
> +
> +static void
> +riscv_free_table_jump_htab (riscv_table_jump_htab_t *htab)
> +{
> +  free (htab->names);
> +  free (htab->savings);
> +  free (htab->tbj_indexes);
> +  htab_delete (htab->tbljt_htab);
> +  htab_delete (htab->tbljalt_htab);
> +}
> +
> +static bool
> +riscv_update_table_jump_entry (htab_t htab,
> +                   bfd_vma addr,
> +                   unsigned int benefit,
> +                   const char *name)
> +{
> +  riscv_table_jump_htab_entry search = {addr, 0, NULL, 0};
> +  riscv_table_jump_htab_entry *entry = htab_find (htab, &search);
> +
> +  if (entry == NULL)
> +    {
> +      riscv_table_jump_htab_entry **slot =
> +    (riscv_table_jump_htab_entry **) htab_find_slot (
> +      htab, &search, INSERT);
> +
> +      BFD_ASSERT (*slot == NULL);
> +
> +      *slot = (riscv_table_jump_htab_entry *) bfd_zmalloc (
> +        sizeof (riscv_table_jump_htab_entry));
> +
> +      if (*slot == NULL)
> +    return false;
> +
> +      (*slot)->address = addr;
> +      (*slot)->benefit = benefit;
> +      (*slot)->name = name;
> +    }
> +  else {
> +    /* account for jump entry size */
> +    entry->benefit +=  benefit + RISCV_ELF_WORD_BYTES;
> +  }
> +  return true;
> +}
> +
>  /* Compute a hash of a local hash entry.  We use elf_link_hash_entry
>     for local symbol so that we can handle local STT_GNU_IFUNC symbols
>     as global symbol.  We reuse indx and dynstr_index for local symbol
> @@ -632,6 +744,25 @@ riscv_elf_get_local_sym_hash (struct 
> riscv_elf_link_hash_table *htab,
>    return &ret->elf;
>  }
>
> +#if ZCMT_PRINT_TABLE_JUMP_ENTRIES
> +static void
> +print_tablejump_entries(riscv_table_jump_htab_t *table_jump_htab)
> +{
> +
> +  if (table_jump_htab->tbj_indexes[0])
> +    printf("cm.jt:\n");
> +  for (unsigned int z = 0; z < 32 && table_jump_htab->tbj_indexes[z] 
> != 0; z ++)
> +    printf ("\tindex=%d, sym name=%s, address=0x%08lx, savings=%u\n",
> +    z, table_jump_htab->names[z], table_jump_htab->tbj_indexes[z], 
> table_jump_htab->savings[z]);
> +
> +  if (table_jump_htab->tbj_indexes[32])
> +    printf("cm.jalt:\n");
> +  for (unsigned int z = 32; z < 256 && 
> table_jump_htab->tbj_indexes[z] != 0; z ++)
> +    printf ("\tindex=%d, sym name=%s, address=0x%08lx, savings=%u\n",
> +    z, table_jump_htab->names[z], table_jump_htab->tbj_indexes[z], 
> table_jump_htab->savings[z]);
> +}
> +#endif
> +
>  /* Destroy a RISC-V elf linker hash table.  */
>
>  static void
> @@ -645,6 +776,15 @@ riscv_elf_link_hash_table_free (bfd *obfd)
>    if (ret->loc_hash_memory)
>      objalloc_free ((struct objalloc *) ret->loc_hash_memory);
>
> +  if (ret->table_jump_htab)
> +    {
> +      #if ZCMT_PRINT_TABLE_JUMP_ENTRIES
> +    print_tablejump_entries(ret->table_jump_htab);
> +      #endif
> +      riscv_free_table_jump_htab (ret->table_jump_htab);
> +      free (ret->table_jump_htab);
> +    }
> +
>    _bfd_elf_link_hash_table_free (obfd);
>  }
>
> @@ -699,6 +839,16 @@ riscv_elf_link_hash_table_create (bfd *abfd)
>        return NULL;
>      }
>
> +  ret->table_jump_htab = (riscv_table_jump_htab_t *) bfd_zmalloc (
> +      sizeof (riscv_table_jump_htab_t));
> +
> +  if (ret->table_jump_htab == NULL
> +    || !riscv_init_table_jump_htab(ret->table_jump_htab))
> +    {
> +      riscv_elf_link_hash_table_free (abfd);
> +      return NULL;
> +    }
> +
>    ret->max_alignment = (bfd_vma) -1;
>    ret->max_alignment_for_gp = (bfd_vma) -1;
>
> @@ -920,6 +1070,75 @@ bad_static_reloc (bfd *abfd, unsigned r_type, 
> struct elf_link_hash_entry *h)
>    return false;
>  }
>
> +static bool
> +riscv_use_table_jump (struct bfd_link_info *info)
> +{
> +  unsigned xlen = ARCH_SIZE;
> +  riscv_subset_list_t subsets;
> +  bool ret;
> +
> +  /* if --no-relax */
> +  if (info->disable_target_specific_optimizations > 0)
> +    return false;
> +
> +  if (!bfd_link_executable (info))
> +    return false;
> +
> +  bfd *obfd = info->output_bfd;
> +  obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
> +
> +  subsets.head = NULL;
> +  subsets.tail = NULL;
> +  subsets.arch_str = NULL;
> +
> +  riscv_parse_subset_t riscv_rps_ld_out =
> +    {&subsets, _bfd_error_handler, &xlen, NULL, false};
> +
> +  if (!riscv_parse_subset (&riscv_rps_ld_out, 
> out_attr[Tag_RISCV_arch].s))
> +    return false;
> +
> +  ret = riscv_subset_supports (&riscv_rps_ld_out, "zcmt");
> +  riscv_release_subset_list (&subsets);
> +
> +  return ret;
> +}
> +
> +static bool
> +bfd_elf_riscv_make_tablejump_section (bfd *abfd, struct bfd_link_info 
> *info)
> +{
> +  asection *sec;
> +  struct riscv_elf_link_hash_table *htab;
> +  const struct elf_backend_data *bed;
> +
> +  /* Skip if no Zcmt or --no-relax.  */
> +  if (!riscv_use_table_jump (info))
> +    return true;
> +
> +  bed = get_elf_backend_data (abfd);
> +  htab = riscv_elf_hash_table (info);
> +  sec = bfd_get_linker_section (abfd, TABLE_JUMP_SEC_NAME);
> +
> +  if (sec != NULL)
> +    return true;
> +
> +  if (htab->table_jump_htab->tablejump_sec == NULL)
> +    {
> +      sec = bfd_make_section_anyway_with_flags (abfd, 
> TABLE_JUMP_SEC_NAME,
> +          (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
> +          | SEC_IN_MEMORY | SEC_KEEP));
> +
> +      if (sec == NULL
> +      || !bfd_set_section_alignment (sec, bed->s->log_file_align)
> +      || !bfd_set_section_size (sec, 256 * RISCV_ELF_WORD_BYTES))
> +    return false;
> +
> +      htab->table_jump_htab->tablejump_sec = sec;
> +      htab->table_jump_htab->tablejump_sec_owner = abfd;
> +    }
> +
> +  return true;
> +}
> +
>  /* Look through the relocs for a section during the first phase, and
>     allocate space in the global offset table or procedure linkage
>     table.  */
> @@ -1266,6 +1485,9 @@ riscv_elf_check_relocs (bfd *abfd, struct 
> bfd_link_info *info,
>      }
>      }
>
> +  if (!bfd_elf_riscv_make_tablejump_section (abfd, info))
> +    return false;
> +
>    return true;
>  }
>
> @@ -1977,6 +2199,10 @@ perform_relocation (const reloc_howto_type *howto,
>              bfd *input_bfd,
>              bfd_byte *contents)
>  {
> +  /* R_RISCV_TABLE_JUMP expected for zcmt.  */
> +  if (ELFNN_R_TYPE (rel->r_info) == R_RISCV_TABLE_JUMP)
> +     return bfd_reloc_ok;
> +
>    if (howto->pc_relative)
>      value -= sec_addr (input_section) + rel->r_offset;
>
> @@ -3353,6 +3579,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
>        unresolved_reloc = false;
>        break;
>
> +    case  R_RISCV_TABLE_JUMP:
> +      break;
> +
>      default:
>        r = bfd_reloc_notsupported;
>      }
> @@ -4869,6 +5098,94 @@ typedef bool (*relax_func_t) (bfd *, asection 
> *, asection *,
>                    riscv_pcgp_relocs *,
>                    bool undefined_weak);
>
> +static htab_t
> +riscv_get_table_jump_htab (struct bfd_link_info *info, unsigned int 
> link_reg)
> +{
> +  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
> +  riscv_table_jump_htab_t *tbj_htab = htab->table_jump_htab;
> +
> +  BFD_ASSERT (tbj_htab != NULL);
> +
> +  if (link_reg == 0)
> +    return tbj_htab->tbljt_htab;
> +
> +  if (link_reg == X_RA
> +      && tbj_htab->tbljalt_index >= CMJALT_INDEX)
> +    return tbj_htab->tbljalt_htab;
> +
> +  return NULL;
> +}
> +
> +static const char*
> +riscv_get_symbol_name (bfd *abfd, Elf_Internal_Rela *rel)
> +{
> +  unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
> +  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
> +  const char *name;
> +
> +  if (!symtab_hdr->contents)
> +    return NULL;
> +
> +  if (ELFNN_R_SYM (rel->r_info) < symtab_hdr->sh_info)
> +    {
> +      /* A local symbol.  */
> +      Elf_Internal_Sym *sym = ((Elf_Internal_Sym *) symtab_hdr->contents
> +        + r_symndx);
> +      name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
> +    }
> +  else
> +    {
> +      struct elf_link_hash_entry *h;
> +      unsigned indx = r_symndx - 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 != NULL && h->type != STT_GNU_IFUNC)
> +    name = h->root.root.string;
> +      else
> +    /* We do not handle STT_GNU_IFUNC currently.  */
> +    return NULL;
> +    }
> +
> +  return name;
> +}
> +
> +static bool
> +_bfd_riscv_table_jump_mark (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
> +               asection *sym_sec ATTRIBUTE_UNUSED,
> +               struct bfd_link_info *link_info,
> +               Elf_Internal_Rela *rel,
> +               bfd_vma symval,
> +               bfd_vma max_alignment ATTRIBUTE_UNUSED,
> +               bfd_vma reserve_size ATTRIBUTE_UNUSED,
> +               bool *again ATTRIBUTE_UNUSED,
> +               riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
> +               bool undefined_weak ATTRIBUTE_UNUSED)
> +{
> +  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
> +  bfd_vma target = bfd_getl32 (contents + rel->r_offset);
> +  if(ELFNN_R_TYPE (rel->r_info) != R_RISCV_JAL)
> +    target = bfd_getl32 (contents + rel->r_offset + 4);
> +  int rd = (target >> OP_SH_RD) & OP_MASK_RD;
> +  htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);
> +
> +  /* Check if it uses a valid link register.  */
> +  if (tbljal_htab == NULL)
> +    return true;
> +
> +  riscv_table_jump_htab_entry search = {symval, 0, NULL, 0};
> +  riscv_table_jump_htab_entry *entry = htab_find (tbljal_htab, &search);
> +
> +  /* entry->index == 0 when the entry is not used as a table jump 
> entry.  */
> +  if (entry != NULL && entry->index > 0)
> +    {
> +      target = MATCH_CM_JT | ENCODE_ZCMT_INDEX (entry->index-1);
> +      bfd_putl32 (target, contents + rel->r_offset);
> +    }
> +  return true;
> +}
> +
>  /* Relax AUIPC + JALR into JAL.  */
>
>  static bool
> @@ -4900,9 +5217,12 @@ _bfd_riscv_relax_call (bfd *abfd, asection 
> *sec, asection *sym_sec,
>        foff += ((bfd_signed_vma) foff < 0 ? -max_alignment : 
> max_alignment);
>      }
>
> -  /* See if this function call can be shortened.  */
> -  if (!VALID_JTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && 
> near_zero))
> -    return true;
> +  /* See if this function call can be shortened or fall back to zcmt
> +     opporunity.  */
> +  if (!VALID_JTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && 
> near_zero )
> +      && !riscv_use_table_jump (link_info)) {
> +    return true;
> +  }
>
>    /* Shorten the function call.  */
>    BFD_ASSERT (rel->r_offset + 8 <= sec->size);
> @@ -4935,6 +5255,26 @@ _bfd_riscv_relax_call (bfd *abfd, asection 
> *sec, asection *sym_sec,
>        auipc = MATCH_JALR | (rd << OP_SH_RD);
>      }
>
> +  /* Table jump profiling stage. It will be moved out of the 
> relax_call function.  */
> +  if (link_info->relax_pass == 0)
> +    {
> +      /* Early stop to prevent _bfd_riscv_relax_call to delete bytes 
> in pass 0.  */
> +      if (link_info->relax_trip != 0)
> +         return true;
> +
> +      htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);
> +      const char *name = riscv_get_symbol_name (abfd, rel);
> +      unsigned int benefit = len - 2 ;
> +
> +      if (tbljal_htab == NULL
> +          || name == NULL
> +          || benefit == 0)
> +        return true;
> +
> +     *again = true;
> +      return riscv_update_table_jump_entry (tbljal_htab, symval, 
> benefit, name);
> +    }
> +
>    /* Replace the R_RISCV_CALL reloc.  */
>    rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), r_type);
>    /* Replace the AUIPC.  */
> @@ -5355,6 +5695,159 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
>    return true;
>  }
>
> +static bool
> +_bfd_riscv_record_jal (bfd *abfd,
> +             asection *sec ATTRIBUTE_UNUSED,
> +             asection *sym_sec ATTRIBUTE_UNUSED,
> +             struct bfd_link_info *link_info,
> +             Elf_Internal_Rela *rel,
> +             bfd_vma symval,
> +             bfd_vma max_alignment ATTRIBUTE_UNUSED,
> +             bfd_vma reserve_size ATTRIBUTE_UNUSED,
> +             bool *again ATTRIBUTE_UNUSED,
> +             riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
> +             bool undefined_weak ATTRIBUTE_UNUSED)
> +{
> +  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
> +  bfd_vma jal = bfd_getl32 (contents + rel->r_offset);
> +  unsigned int rd = (jal >> OP_SH_RD) & OP_MASK_RD;
> +  htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);
> +  const char *name = riscv_get_symbol_name (abfd, rel);
> +
> +  if (link_info->relax_pass == 1
> +      && ((jal ^ MATCH_CM_JT) & MASK_CM_JALT) == 0)
> +    {
> +      rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), 
> R_RISCV_TABLE_JUMP);
> +      *again = true;
> +      return riscv_relax_delete_bytes (abfd, sec,
> +          rel->r_offset + 2, 6, link_info, pcgp_relocs, NULL);
> +    }
> +
> +  if (tbljal_htab == NULL
> +      || name == NULL
> +      || (link_info->relax_pass == 0 && link_info->relax_trip > 0)
> +      || link_info->relax_pass > 0)
> +    return true;
> +
> + *again = true;
> +  return riscv_update_table_jump_entry (tbljal_htab, symval, 2, name);
> +}
> +
> +typedef struct
> +{
> +  riscv_table_jump_htab_t *htab;
> +  unsigned int start;
> +  unsigned int end;
> +} riscv_table_jump_args;
> +
> +static int
> +riscv_ranking_table_jump (void **entry_ptr, void *_arg)
> +{
> +  const riscv_table_jump_htab_entry *entry;
> +  riscv_table_jump_args *arg;
> +  riscv_table_jump_htab_t *htab;
> +  int *savings;
> +  const char **names;
> +  uintNN_t *tbj_indexes;
> +
> +  entry = (const riscv_table_jump_htab_entry *) *entry_ptr;
> +  arg = (riscv_table_jump_args*) _arg;
> +  htab = (riscv_table_jump_htab_t *) arg->htab;
> +
> +  savings = htab->savings;
> +  names = htab->names;
> +  tbj_indexes = htab->tbj_indexes;
> +
> +  /* search insert position and rank.  */
> +  unsigned int left = arg->start;
> +  unsigned int right = arg->end + 1;
> +
> +  while (left < right)
> +    {
> +      unsigned int mid = (left + right) / 2;
> +      /* `entry->benefit != 0` helps prioritize index with a zero 
> benefit.  */
> +      if (savings[mid] == entry->benefit && entry->benefit != 0)
> +    {
> +      left = mid;
> +      break;
> +    }
> +      else if (savings[mid] == 0
> +      || savings[mid] < entry->benefit)
> +    right = mid;
> +      else
> +    left = mid + 1;
> +    }
> +
> +  for (unsigned int idx = arg->end; idx > left; idx--)
> +    {
> +      tbj_indexes[idx] = tbj_indexes[idx-1];
> +      savings[idx] = savings[idx-1];
> +      names[idx] = names[idx-1];
> +    }
> +
> +  if (left <= arg->end)
> +    {
> +      tbj_indexes[left] = (uintNN_t) entry->address;
> +      savings[left] = entry->benefit;
> +      names[left] = entry->name;
> +    }
> +  return true;
> +}
> +
> +static bool
> +riscv_record_table_jump_index (htab_t htab, riscv_table_jump_args 
> *args, bool iscmjl)
> +{
> +  unsigned int idx;
> +  riscv_table_jump_htab_t *tbj_htab = args->htab;
> +  riscv_table_jump_htab_entry search;
> +  riscv_table_jump_htab_entry *entry = NULL;
> +
> +  for (idx = args->start; idx <= args->end && 
> tbj_htab->tbj_indexes[idx]; idx++)
> +    {
> +      search = (riscv_table_jump_htab_entry)
> +      {tbj_htab->tbj_indexes[idx], 0, NULL, 0};
> +      entry = htab_find (htab, &search);
> +
> +      BFD_ASSERT (entry != NULL);
> +      entry->index = idx + 1;
> +      tbj_htab->total_saving += tbj_htab->savings[idx];
> +    }
> +
> +  /* True if there is at least one entry in table jump section.  */
> +  if (entry && entry->index)
> +    tbj_htab->end_idx = tbj_htab->tbljt_index = entry->index;
> +  if (iscmjl)
> +    tbj_htab->tbljt_index = entry->index;
> +
> +  return true;
> +}
> +
> +static bool
> +riscv_table_jump_profiling (riscv_table_jump_htab_t *table_jump_htab,
> +    riscv_table_jump_args *args)
> +{
> +  args->start = 0, args->end = 31;
> +  /* Do a ranking.  */
> +  htab_traverse (table_jump_htab->tbljt_htab,
> +    riscv_ranking_table_jump,
> +    args);
> +  /* cmjl enteries and update tbljt_index.  */
> +  riscv_record_table_jump_index (
> +      table_jump_htab->tbljt_htab,
> +      args,
> +      true);
> +
> +  args->start = 32, args->end = 255;
> +  htab_traverse (table_jump_htab->tbljalt_htab,
> +    riscv_ranking_table_jump,
> +    args);
> +  riscv_record_table_jump_index (
> +      table_jump_htab->tbljalt_htab,
> +      args,
> +      false);
> +  return true;
> +}
> +
>  /* Called by after_allocation to set the information of data segment
>     before relaxing.  */
>
> @@ -5366,6 +5859,41 @@ bfd_elfNN_riscv_set_data_segment_info (struct 
> bfd_link_info *info,
>    htab->data_segment_phase = data_segment_phase;
>  }
>
> +
> +static void  cleanup_pad_CMJALT(riscv_table_jump_htab_t *htab)
> +{
> +  unsigned int end_idx = htab->end_idx;
> +  unsigned int jt_index = htab->tbljt_index;
> +  unsigned int alt_index = htab->tbljalt_index;
> +
> +  /* Nothing to clean up if no entries,set up cmjalt index.  */
> +  if (htab->tbljalt_index == 0)
> +    {
> +      htab->tbljalt_index = jt_index;
> +      return ;
> +    }
> +
> +  /* Check if there's enough "room" to do cleanup.  */
> +  unsigned int entries_after_cmj = end_idx - (CMJALT_INDEX - 1);
> +  unsigned int alt_space = CMJALT_INDEX - jt_index;
> +
> +  if (alt_space > entries_after_cmj)
> +    {
> +      /* Clean up from CMJALT_INDEX up to current alt_index. */
> +      for (unsigned int i = CMJALT_INDEX; i < alt_index; i++)
> +    {
> +      htab->total_saving -= htab->savings[i];
> +      htab->tbj_indexes[i] = 0;
> +      htab->savings[i] = 0;
> +      htab->names[i] = NULL;
> +    }
> +
> +    /* Reset alt index to jump-table index.  */
> +    htab->tbljalt_index = jt_index;
> +    }
> +    return ;
> +}
> +
>  /* Relax a section.
>
>     Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs and
> @@ -5386,6 +5914,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>    bfd_vma max_alignment, reserve_size = 0;
>    riscv_pcgp_relocs pcgp_relocs;
>    static asection *first_section = NULL;
> +  riscv_table_jump_htab_t *table_jump_htab = htab->table_jump_htab;
> +  struct elf_link_hash_entry *jvt_sym;
> +  bool is_zcmt = riscv_use_table_jump (info);
>
>    *again = false;
>
> @@ -5426,6 +5957,80 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>        htab->max_alignment = max_alignment;
>      }
>
> +  /* relax_trip 0:
> +     Record symbol address and expected size saving of each relocation
> +     that can be replaced by table jump instructions.
> +
> +     relax_trip 1:
> +     Rank the best 32 relocations to replace for cm.jt and the best 224
> +     relocations for cm.jalt in terms of the total size saved.
> +
> +     relax_trip 2:
> +     Check if table jump can reduce the size, and delete the whole table
> +     jump section if the size will not be reduced.
> +
> +     relax_trip 3: Trim unused slots in the table jump section.
> +     If table jump can save size, and then we replace all targeted
> +     instructions/instruction pairs(e.g. auipc+jalr) to table jump
> +     instructions with the index encoded.  */
> +
> +  if (info->relax_pass == 0
> +      && is_zcmt)
> +    {
> +      /* Avoid size savings of relocations to be recoreded multiple 
> times.  */
> +      if (info->relax_trip == 0 && *(htab->data_segment_phase) != 0 )
> +        return true;
> +      /* Rank the entries, and calculate the expected total saving.  */
> +      else if (info->relax_trip == 1)
> +    {
> +      /*come back for trip 2.  */
> +      *again = true;
> +      /* Profiling stage finished.  */
> +      if (table_jump_htab->end_idx != 0)
> +        return true;
> +
> +      riscv_table_jump_args args = {table_jump_htab, 0, 0};
> +      /* Estimate size savings if table jump is used.  */
> +      riscv_table_jump_profiling (table_jump_htab, &args);
> +      return true;
> +    }
> +      /* Skip generating table jump instructions if they do not help 
> reduce code size.
> +     Or install the internal zcmt symbol  definition.  */
> +      else if (info->relax_trip == 2)
> +    {
> +      /* check the min size to be saved  */
> +      if (table_jump_htab->total_saving <= info->min_zcmt_size)
> +    return true;
> +
> +      /* Table jump entry symbol definition.  */
> +      jvt_sym = elf_link_hash_lookup (elf_hash_table (info),
> +                      RISCV_TABLE_JUMP_BASE_SYMBOL,
> +                      true, false, true);
> +      jvt_sym->root.u.def.section = bfd_abs_section_ptr;
> +      /* come back for trip 3.  */
> +      *again = true;
> +    }
> +      /* cleanup the tables entries and update the section content.  */
> +      else if (info->relax_trip == 3)
> +    {
> +      /* Table jump entry section is trimmed.  */
> +      if (table_jump_htab->end_idx < 0)
> +        return true;
> +
> +      cleanup_pad_CMJALT(table_jump_htab);
> +      /* buffer to hold the table enteries.  */
> +      int cmt_jbl_section_content_size = (table_jump_htab->tbljalt_index
> +                          * RISCV_ELF_WORD_BYTES);
> +      bfd_byte *buf = (bfd_byte*) 
> bfd_malloc(cmt_jbl_section_content_size);
> +      /* copy the table entries. */
> +      for (short int index = 0; index < 
> table_jump_htab->tbljalt_index ; index++)
> + bfd_putl32(table_jump_htab->tbj_indexes[index],buf+(index *4));
> +
> + elf_section_data(table_jump_htab->tablejump_sec)->this_hdr.contents=buf;
> +      /* we are done ,tbljalt_index used to patch the relocation.  */
> +      table_jump_htab->end_idx = -1;
> +    }
> +  }
>    /* Examine and consider relaxing each reloc.  */
>    for (i = 0; i < sec->reloc_count; i++)
>      {
> @@ -5439,11 +6044,16 @@ _bfd_riscv_relax_section (bfd *abfd, asection 
> *sec,
>
>        relax_func = NULL;
>        riscv_relax_delete_bytes = NULL;
> +
>        if (info->relax_pass == 0)
>      {
> +      if (!is_zcmt)
> +        return true;
>        if (type == R_RISCV_CALL
>            || type == R_RISCV_CALL_PLT)
>          relax_func = _bfd_riscv_relax_call;
> +      else if (type == R_RISCV_JAL)
> +        relax_func = _bfd_riscv_record_jal;
>        else if (type == R_RISCV_HI20
>             || type == R_RISCV_LO12_I
>             || type == R_RISCV_LO12_S)
> @@ -5459,25 +6069,41 @@ _bfd_riscv_relax_section (bfd *abfd, asection 
> *sec,
>                 || type == R_RISCV_PCREL_LO12_S))
>          relax_func = _bfd_riscv_relax_pc;
>        else
> -        continue;
> +       continue;
> +
>        riscv_relax_delete_bytes = _riscv_relax_delete_piecewise;
>
>        /* Only relax this reloc if it is paired with R_RISCV_RELAX.  */
> -      if (i == sec->reloc_count - 1
> +      if ((i == sec->reloc_count - 1
>            || ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
>            || rel->r_offset != (rel + 1)->r_offset)
> +          && !is_zcmt)
>          continue;
>
> +      /*  Replace JAL/JALR with cmjlt/ cmjalt.  */
> +      if (info->relax_trip == 3)
> +        relax_func = _bfd_riscv_table_jump_mark;
> +
>        /* Skip over the R_RISCV_RELAX.  */
>        i++;
> -    }
> -      else if (info->relax_pass == 1 && type == R_RISCV_ALIGN)
> +}
> +      else if (info->relax_pass == 1
> +           && type == R_RISCV_ALIGN)
>      {
>        relax_func = _bfd_riscv_relax_align;
>        riscv_relax_delete_bytes = _riscv_relax_delete_immediate;
>      }
> +      else if (info->relax_pass == 1
> +           && (type == R_RISCV_JAL
> +           || type == R_RISCV_CALL
> +           || type == R_RISCV_CALL_PLT))
> +    {
> +      relax_func = _bfd_riscv_record_jal;
> +      riscv_relax_delete_bytes = _riscv_relax_delete_immediate;
> +     }
> +
>        else
> -    continue;
> +       continue;
>
>        data->relocs = relocs;
>
> @@ -5648,6 +6274,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>      free (relocs);
>    riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
>
> +  /* If no size is saved, exclude the table jump section.  */
> +  if ((info->relax_pass == 1)
> +      && (table_jump_htab->total_saving == 0)
> +      && is_zcmt)
> +    table_jump_htab->tablejump_sec->flags |= SEC_EXCLUDE;
> +
>    return ret;
>  }
>
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index 085d77923a0..989689969ed 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -958,6 +958,23 @@ static const reloc_howto_type 
> howto_table_internal[] =
>       0,                /* src_mask */
>       ENCODE_STYPE_IMM (-1U),    /* dst_mask */
>       false),            /* pcrel_offset */
> +
> +  /* Table jump entries.  */
> +  HOWTO (R_RISCV_TABLE_JUMP,        /* type */
> +     0,                /* rightshift */
> +     1,                /* size */
> +     16,                /* bitsize */
> +     true,                /* pc_relative */
> +     0,                /* bitpos */
> +     complain_overflow_dont,    /* complain_on_overflow */
> +     bfd_elf_generic_reloc,        /* special_function */
> +     "R_RISCV_TABLE_JUMP",    /* name */
> +     false,                /* partial_inplace */
> +     0,                /* src_mask */
> +     ENCODE_ZCMT_INDEX (-1U),    /* dst_mask */
> +     true),                /* pcrel_offset */
> +
> +   EMPTY_HOWTO (226),
>  };
>
>  /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index df60c206b82..25404ddd773 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -4854,6 +4854,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
>        break;
>
>      case BFD_RELOC_RISCV_JMP:
> +      /* j and jal can be relaxed into cm.jalt or cm.jt if zcmt is 
> used.  */
> +      if (riscv_subset_supports (&riscv_rps_as, "zcmt"))
> +    {
> +      relaxable = true;
> +      fixP->fx_tcbit = riscv_opts.relax;
> +    }
>        if (fixP->fx_addsy)
>      {
>        /* Fill in a tentative value to improve objdump readability.  */
> @@ -5433,7 +5439,22 @@ md_convert_frag_branch (fragS *fragp)
>          /* Invert the branch condition.  Branch over the jump. */
>          insn = bfd_getl16 (buf);
>          insn ^= MATCH_C_BEQZ ^ MATCH_C_BNEZ;
> -        insn |= ENCODE_CBTYPE_IMM (6);
> +      if (riscv_subset_supports (&riscv_rps_as, "zcmt"))
> +          {
> +        symbolS *sym = symbol_new (FAKE_LABEL_NAME , now_seg, fragp,
> +                     fragp->fr_fix + fragp->fr_var);
> +        fixp = fix_new (fragp,
> +                buf - (bfd_byte *)fragp->fr_literal,
> +                2,
> +                sym,
> +                0,
> +                false,
> +                BFD_RELOC_RISCV_RVC_BRANCH);
> +        fixp->fx_file = fragp->fr_file;
> +        fixp->fx_line = fragp->fr_line;
> +          }
> +        else
> +          insn |= ENCODE_CBTYPE_IMM (6);
>          bfd_putl16 (insn, buf);
>          buf += 2;
>          goto jump;
> @@ -5460,7 +5481,23 @@ md_convert_frag_branch (fragS *fragp)
>        /* Invert the branch condition.  Branch over the jump. */
>        insn = bfd_getl32 (buf);
>        insn ^= MATCH_BEQ ^ MATCH_BNE;
> -      insn |= ENCODE_BTYPE_IMM (8);
> +      if (riscv_subset_supports (&riscv_rps_as, "zcmt"))
> +    {
> +      symbolS *sym = (symbolS *) local_symbol_make (
> +            FAKE_LABEL_NAME, now_seg, fragp,
> +            fragp->fr_fix + fragp->fr_var);
> +      fixp = fix_new (fragp,
> +              buf - (bfd_byte *)fragp->fr_literal,
> +              4,
> +              sym,
> +              0,
> +              false,
> +              BFD_RELOC_12_PCREL);
> +      fixp->fx_file = fragp->fr_file;
> +      fixp->fx_line = fragp->fr_line;
> +    }
> +      else
> +    insn |= ENCODE_BTYPE_IMM (8);
>        bfd_putl32 (insn, buf);
>        buf += 4;
>
> diff --git a/include/bfdlink.h b/include/bfdlink.h
> index 00fe0f8c7c8..b40d23b516d 100644
> --- a/include/bfdlink.h
> +++ b/include/bfdlink.h
> @@ -769,6 +769,9 @@ struct bfd_link_info
>    /* The maximum cache size.  Backend can use cache_size and and
>       max_cache_size to decide if keep_memory should be honored.  */
>    bfd_size_type max_cache_size;
> +
> +   /* Minimum size to be saved with ZCMT sections.  */
> +  bfd_size_type min_zcmt_size;
>  };
>
>  /* Some forward-definitions used by some callbacks.  */
> diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> index 2ea1ae82eb6..f2f5f8618e3 100644
> --- a/include/elf/riscv.h
> +++ b/include/elf/riscv.h
> @@ -95,6 +95,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
>    RELOC_NUMBER (R_RISCV_TLSDESC_LOAD_LO12, 63)
>    RELOC_NUMBER (R_RISCV_TLSDESC_ADD_LO12, 64)
>    RELOC_NUMBER (R_RISCV_TLSDESC_CALL, 65)
> +  /* Zcmt Specific Relocation.  */
> +  RELOC_NUMBER (R_RISCV_TABLE_JUMP, 226)
>  END_RELOC_NUMBERS (R_RISCV_max)
>
>  /* Internal relocations used exclusively by the relaxation pass.  */
> @@ -131,6 +133,14 @@ END_RELOC_NUMBERS (R_RISCV_max)
>  /* The name of the global pointer symbol.  */
>  #define RISCV_GP_SYMBOL "__global_pointer$"
>
> +/* Zcmt table jump symbol.  */
> +#define RISCV_TABLE_JUMP_BASE_SYMBOL "__jvt_base$"
> +
> +#define TABLE_JUMP_SEC_NAME ".jvt"
> +
> +/* CMJALT Start index.  */
> +#define CMJALT_INDEX 32
> +
>  /* Processor specific dynamic array tags.  */
>  #define DT_RISCV_VARIANT_CC (DT_LOPROC + 1)
>
> diff --git a/ld/ldlex.h b/ld/ldlex.h
> index 24cac1cdfc0..8158aa223a8 100644
> --- a/ld/ldlex.h
> +++ b/ld/ldlex.h
> @@ -475,6 +475,7 @@ enum option_values
>    /* Used by emultempl/elf-i386-glibc.em.  */
>    OPTION_GNU_TLS_VERSION_TAG,
>    OPTION_NO_GNU_TLS_VERSION_TAG,
> +  OPTION_MIN_ZCMT_SIZE,
>  };
>
>  /* The initial parser states.  */
> diff --git a/ld/ldmain.c b/ld/ldmain.c
> index 157f205671e..45b0cf2649d 100644
> --- a/ld/ldmain.c
> +++ b/ld/ldmain.c
> @@ -677,6 +677,8 @@ main (int argc, char **argv)
>    link_info.allow_undefined_version = true;
>    link_info.keep_memory = true;
>    link_info.max_cache_size = (bfd_size_type) -1;
> +  /* default min 4 bytes to be saved */
> +  link_info.min_zcmt_size = 4;
>    link_info.combreloc = true;
>    link_info.strip_discarded = true;
>    link_info.prohibit_multiple_definition_absolute = false;
> diff --git a/ld/lexsup.c b/ld/lexsup.c
> index 5cb77992733..1ee90e3a47c 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -447,6 +447,10 @@ static const struct ld_option ld_options[] =
>      OPTION_MAX_CACHE_SIZE},
>      '\0', NULL, N_("Set the maximum cache size to SIZE bytes"),
>      TWO_DASHES },
> +  { {"min-zcmt-size=SIZE", required_argument, NULL,
> +     OPTION_MIN_ZCMT_SIZE},
> +    '\0', NULL, N_("Set the minimum size to be saved with zcmt and 
> SIZE in bytes"),
> +    TWO_DASHES },
>    { {"relax", no_argument, NULL, OPTION_RELAX},
>      '\0', NULL, N_("Reduce code size by using target specific 
> optimizations"), TWO_DASHES },
>    { {"no-relax", no_argument, NULL, OPTION_NO_RELAX},
> @@ -1777,6 +1781,15 @@ parse_args (unsigned argc, char **argv)
>        }
>        break;
>
> +    case OPTION_MIN_ZCMT_SIZE:
> +      {
> +        char *end;
> +        bfd_size_type zcmt_size = strtoul (optarg, &end, 0);
> +        if (*end != '\0')
> +          fatal (_("%P: invalid cache memory size: %s\n"), optarg);
> +        link_info.min_zcmt_size = zcmt_size;
> +      }
> +      break;
>      case OPTION_HASH_SIZE:
>        {
>          bfd_size_type new_size;
> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp 
> b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> index b0d510ac8da..1f37a9b0fac 100644
> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> @@ -127,6 +127,7 @@ if [istarget "riscv*-*-*"] {
>      run_dump_test "c-lui"
>      run_dump_test "c-lui-2"
>      run_dump_test "disas-jalr"
> +    run_dump_test "zcmt_relax"
>      run_dump_test "pcrel-lo-addend"
>      run_dump_test "pcrel-lo-addend-2a"
>      run_dump_test "pcrel-lo-addend-2b"
> diff --git a/ld/testsuite/ld-riscv-elf/zcmt_relax.d 
> b/ld/testsuite/ld-riscv-elf/zcmt_relax.d
> new file mode 100644
> index 00000000000..4ea4e53fb49
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/zcmt_relax.d
> @@ -0,0 +1,18 @@
> +#source: zcmt_relax.s
> +#as: 
> -march=rv32imafdb_zicbop_zicond_zicsr_zihintpause_zimop_zaamo_zalrsc_zfa_zca_zcb_zcf_zcmop_zcmp_zcmt_zba_zbb_zbs
> +#ld: -melf32lriscv -Tzcmt_relax.ld --min-zcmt-size=6 --defsym 
> foo=0x150000 --defsym foo_1=0x150010
> +#objdump: -d
> +
> +.*:     file format .*
> +
> +Disassembly of section \.text:
> +
> +[0-9a-f]+ <main>:
> +^\s+[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+auipc\s+ra,0x[0-9A-Fa-f]+$
> +^\s*[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+jalr\s+ra(?:\s+#\s*[0-9A-Fa-f]+(?:\s+<[^>]+>)?)?$
> +^\s*[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+cm\.jt\s+[0-9A-Fa-f]+$
> +^\s+[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+auipc\s+ra,0x[0-9A-Fa-f]+$
> +^\s*[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+jalr\s+[-+]?[0-9A-Fa-f]+\(ra\)\s*#\s*[0-9A-Fa-f]+\s+<[^>]+>$
> +^\s*[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+cm\.jt\s+[0-9A-Fa-f]+$
> +^\s*[0-9A-Fa-f]+:\s+[0-9A-Fa-f]+\s+cm\.jt\s+[0-9A-Fa-f]+$
> +#pass
> diff --git a/ld/testsuite/ld-riscv-elf/zcmt_relax.ld 
> b/ld/testsuite/ld-riscv-elf/zcmt_relax.ld
> new file mode 100644
> index 00000000000..7ec7c98a45b
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/zcmt_relax.ld
> @@ -0,0 +1,38 @@
> +/* linker.ld - minimal RISC-V linker script with __jvt_base$ */
> +
> +ENTRY(main)   /* program entry point */
> +
> +SECTIONS
> +{
> +    /* Code section */
> +    .text : ALIGN(4)
> +    {
> +        *(.text*)
> +    }
> +
> +    /* Jump Vector Table (JVT) section */
> +    .jvt : ALIGN(8)
> +    {
> +        __jvt_base$ = .;     /* define the base symbol for the JVT */
> +        KEEP(*(.jvt*))       /* keep all JVT entries */
> +    }
> +
> +    /* Read-only data */
> +    .rodata : ALIGN(4)
> +    {
> +        *(.rodata*)
> +    }
> +
> +    /* Data section */
> +    .data : ALIGN(4)
> +    {
> +        *(.data*)
> +    }
> +
> +    /* BSS section */
> +    .bss : ALIGN(4)
> +    {
> +        *(.bss*)
> +        *(COMMON)
> +    }
> +}
> diff --git a/ld/testsuite/ld-riscv-elf/zcmt_relax.s 
> b/ld/testsuite/ld-riscv-elf/zcmt_relax.s
> new file mode 100644
> index 00000000000..fec4020cd2c
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/zcmt_relax.s
> @@ -0,0 +1,9 @@
> +.text
> +.global main
> +.p2align 3
> +main:
> +  call foo
> +  tail foo_1
> +  call foo
> +  tail foo_1
> +  tail foo_1
> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> index fa2d44af28f..a2665714680 100644
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -44,6 +44,8 @@ struct riscv_private_data
>  {
>    bfd_vma gp;
>    bfd_vma print_addr;
> +  bfd_vma jvt_base;
> +  bfd_vma jvt_end;
>    bfd_vma hi_addr[OP_MASK_RD + 1];
>    bool to_print_addr;
>    bool has_gp;
> @@ -963,6 +965,44 @@ riscv_disassemble_insn (bfd_vma memaddr,
>        init = true;
>      }
>
> +  if (info->private_data == NULL)
> +    {
> +      bfd_vma sym_val;
> +
> +      pd = info->private_data = xcalloc (1, sizeof (struct 
> riscv_private_data));
> +      pd->gp = -1;
> +      pd->print_addr = -1;
> +      pd->jvt_base = -1;
> +      pd->jvt_end = -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]), 
> RISCV_GP_SYMBOL) == 0)
> +        pd->gp = bfd_asymbol_value (info->symtab[i]);
> +      /* Read the address of table jump entries.  */
> +      else if (strcmp (bfd_asymbol_name (info->symtab[i]),
> +                  RISCV_TABLE_JUMP_BASE_SYMBOL) == 0)
> +        pd->jvt_base = bfd_asymbol_value (info->symtab[i]);
> +    }
> +
> +      /* Calculate the closest symbol from jvt base to determine the 
> size of table jump
> +     entry section.  */
> +      if (pd->jvt_base != 0)
> +    {
> +      for (i = 0; i < info->symtab_size; i++)
> +        {
> +          sym_val = bfd_asymbol_value (info->symtab[i]);
> +          if (sym_val > pd->jvt_base && sym_val < pd->jvt_end)
> +        pd->jvt_end = sym_val;
> +        }
> +    }
> +    }
> +  else
> +    pd = info->private_data;
> +
>    insnlen = riscv_insn_length (word);
>
>    /* RISC-V instructions are always little-endian.  */
>



More information about the Binutils mailing list