[RFC PATCH 4/5] RISC-V: Decode Zcmt JVT entries in objdump

Jiawei jiawei@iscas.ac.cn
Thu Sep 24 14:47:04 GMT 2026


On 2026/9/24 21:06, Kito Cheng wrote:
> Could you add a testcase, also do not rely on linker optimization?
Okay, thanks for the suggestion.

Jiawei
>
> e.g.
> ```
>          .text
> foo:
>          cm.jt 0
>
> bar:
>          cm.jalt 32
>
> .section .riscv.jvt, "ax"
>    .word foo # 0
> .rept 31
>    .word 0
> .endr
>    .word bar   # 32
> ```
> Jiawei <jiawei@iscas.ac.cn> 於 2026年6月27日週六 下午6:49寫道:
>
>> This patch adds the RISC-V disassembler to print JVT table entries
>> and annotate cm.jt and cm.jalt targets when the table is present.
>>
>> opcodes/ChangeLog:
>>
>>          * riscv-dis.c (struct riscv_private_data): Add JVT fields.
>>          (riscv_set_xlen_from_elf): New function.
>>          (maybe_print_jvt_address): Ditto.
>>          (print_insn_args): Annotate JVT target.
>>          (riscv_disassemble_insn): Handle Zcmt decode.
>>          (riscv_disassemble_jvt): New function.
>>          (riscv_init_disasm_info): Init JVT data.
>>          (print_insn_riscv): Handle JVT section.
>>          (disassemble_free_riscv): Free JVT content.
>> ---
>>   opcodes/riscv-dis.c | 164 ++++++++++++++++++++++++++++++++++++++++----
>>   1 file changed, 149 insertions(+), 15 deletions(-)
>>
>> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
>> index ca0d9bfd121..5d5ff0f8b3c 100644
>> --- a/opcodes/riscv-dis.c
>> +++ b/opcodes/riscv-dis.c
>> @@ -47,6 +47,10 @@ struct riscv_private_data
>>     bfd_vma hi_addr[OP_MASK_RD + 1];
>>     bool to_print_addr;
>>     bool has_gp;
>> +  bool has_jvt_base;
>> +  asection *jvt_section;
>> +  bfd_byte *jvt_content;
>> +  bfd_size_type jvt_size;
>>     /* Current XLEN for the disassembler.  */
>>     unsigned xlen;
>>     /* Default ISA specification version.  */
>> @@ -220,6 +224,48 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
>>       pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
>>   }
>>
>> +/* Set pd->xlen from ELF class if not already known.  */
>> +
>> +static void
>> +riscv_set_xlen_from_elf (struct riscv_private_data *pd,
>> +                        struct disassemble_info *info)
>> +{
>> +  if (pd->xlen != 0)
>> +    return;
>> +
>> +  if (info->mach == bfd_mach_riscv64)
>> +    pd->xlen = 64;
>> +  else if (info->mach == bfd_mach_riscv32)
>> +    pd->xlen = 32;
>> +  else if (info->section != NULL)
>> +    {
>> +      Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
>> +      pd->xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
>> +    }
>> +}
>> +
>> +/* Try to print target address of cm.jalt and cm.jt.  */
>> +
>> +static void
>> +maybe_print_jvt_address (struct riscv_private_data *pd, int index)
>> +{
>> +  if (!pd->has_jvt_base || pd->jvt_section == NULL || pd->jvt_content == NULL
>> +      || pd->xlen == 0)
>> +    return;
>> +
>> +  bfd_size_type entry_size = pd->xlen / 8;
>> +  bfd_size_type offset = entry_size * (bfd_size_type) index;
>> +  if (index < 0 || index > (ZCMT_TOTAL_ENTRIES - 1)
>> +      || offset + entry_size > pd->jvt_size)
>> +    return;
>> +
>> +  bfd_byte *packet = pd->jvt_content + offset;
>> +
>> +  pd->to_print_addr = true;
>> +  pd->print_addr = bfd_get_bits (packet, pd->xlen,
>> +                                bfd_big_endian (pd->jvt_section->owner));
>> +}
>> +
>>   /* Get Zcmp reg_list field.  */
>>
>>   static void
>> @@ -747,6 +793,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>>                  case 'I':
>>                    print (info->stream, dis_style_address_offset,
>>                           "%" PRIu64, EXTRACT_ZCMT_INDEX (l));
>> +                 maybe_print_jvt_address (pd, EXTRACT_ZCMT_INDEX (l));
>>                    break;
>>                  default:
>>                    goto undefined_modifier;
>> @@ -1052,17 +1099,7 @@ riscv_disassemble_insn (bfd_vma memaddr,
>>     if (op != NULL)
>>       {
>>         /* If XLEN is not known, get its value from the ELF class.  */
>> -      if (pd->xlen != 0)
>> -       ;
>> -      else if (info->mach == bfd_mach_riscv64)
>> -       pd->xlen = 64;
>> -      else if (info->mach == bfd_mach_riscv32)
>> -       pd->xlen = 32;
>> -      else if (info->section != NULL)
>> -       {
>> -         Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
>> -         pd->xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
>> -       }
>> +      riscv_set_xlen_from_elf (pd, info);
>>
>>         /* If arch has the Zfinx extension, replace FPR with GPR.  */
>>         if (riscv_subset_supports (&pd->riscv_rps_dis, "zfinx"))
>> @@ -1086,10 +1123,12 @@ riscv_disassemble_insn (bfd_vma memaddr,
>>            if ((op->xlen_requirement != 0)
>>                && (op->xlen_requirement != pd->xlen))
>>              continue;
>> -         /* Is this instruction supported by the current architecture?  */
>> +         /* Is this instruction supported by the current architecture?
>> +            Always disassemble ZCMT instructions if __jvt_base$ is present.  */
>>            if (!pd->all_ext
>>                && !riscv_multi_subset_supports (&pd->riscv_rps_dis,
>> -                                              op->insn_class))
>> +                                              op->insn_class)
>> +             && !(pd->has_jvt_base && op->insn_class == INSN_CLASS_ZCMT))
>>              continue;
>>
>>            /* It's a match.  */
>> @@ -1481,6 +1520,51 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED,
>>     return info->bytes_per_chunk;
>>   }
>>
>> +/* DATA is the function address in jump table entry.
>> +   Lookup the address in symbols and print the function name.  */
>> +static int
>> +riscv_disassemble_jvt (bfd_vma memaddr, insn_t data,
>> +                      const bfd_byte *packet,
>> +                      disassemble_info *info)
>> +{
>> +  struct riscv_private_data *pd = info->private_data;
>> +  if (pd == NULL || pd->xlen == 0 || info->section == NULL)
>> +    return -1;
>> +
>> +  bfd_size_type entry_size = pd->xlen / 8;
>> +  bfd_vma offset = memaddr - info->section->vma;
>> +  bfd_size_type entry_offset = (offset / entry_size) * entry_size;
>> +  bfd_size_type entry_delta = offset - entry_offset;
>> +  int idx = entry_offset / entry_size;
>> +  if (idx < 0 || idx > (ZCMT_TOTAL_ENTRIES - 1))
>> +    opcodes_error_handler (_ ("invalid jvt index: %i"), idx);
>> +
>> +  const char *inst_str;
>> +  if (idx <= ZCMT_JT_END)
>> +    inst_str = "jvt.jt";
>> +  else
>> +    inst_str = "jvt.jalt";
>> +
>> +  if (pd->jvt_content != NULL && entry_offset + entry_size <= pd->jvt_size)
>> +    packet = pd->jvt_content + entry_offset;
>> +  data = bfd_get_bits (packet, pd->xlen,
>> +                      bfd_big_endian (info->section->owner));
>> +
>> +  const char *funcname = "<unknown>";
>> +  for (int i = 0; i < info->symtab_size; i++)
>> +    {
>> +      bfd_vma addr = bfd_asymbol_value (info->symtab[i]);
>> +      if (addr == (bfd_vma) data)
>> +       {
>> +         funcname = info->symtab[i]->name;
>> +         break;
>> +       }
>> +    }
>> +  (*info->fprintf_styled_func) (info->stream, dis_style_text, "%s[%i]:\t%s",
>> +                               inst_str, idx, funcname);
>> +  return entry_size - entry_delta;
>> +}
>> +
>>   static bool
>>   riscv_init_disasm_info (struct disassemble_info *info)
>>   {
>> @@ -1493,7 +1577,34 @@ riscv_init_disasm_info (struct disassemble_info *info)
>>       pd->hi_addr[i] = -1;
>>     pd->to_print_addr = false;
>>
>> +  pd->has_jvt_base = false;
>>     pd->has_gp = false;
>> +  pd->jvt_section = NULL;
>> +  pd->jvt_content = NULL;
>> +  pd->jvt_size = 0;
>> +
>> +  if (info->section != NULL)
>> +    {
>> +      bfd *abfd = info->section->owner;
>> +      if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
>> +       {
>> +         asection *s = bfd_get_section_by_name (abfd, TABLE_JUMP_SEC_NAME);
>> +         if (s != NULL && bfd_section_size (s) > 0)
>> +           {
>> +             bfd_size_type size = bfd_section_size (s);
>> +             bfd_byte *buf = (bfd_byte *) xmalloc (size);
>> +             if (bfd_get_section_contents (abfd, s, buf, 0, size))
>> +               {
>> +                 pd->jvt_section = s;
>> +                 pd->jvt_content = buf;
>> +                 pd->jvt_size = size;
>> +               }
>> +             else
>> +               free (buf);
>> +           }
>> +       }
>> +    }
>> +
>>     for (i = 0; i < info->symtab_size; i++)
>>       {
>>         asymbol *sym = info->symtab[i];
>> @@ -1502,9 +1613,18 @@ riscv_init_disasm_info (struct disassemble_info *info)
>>            pd->gp = bfd_asymbol_value (sym);
>>            pd->has_gp = true;
>>          }
>> +
>> +      if (strcmp (bfd_asymbol_name (sym), RISCV_TABLE_JUMP_BASE_SYMBOL) == 0)
>> +       {
>> +         bfd_vma jvt_base = bfd_asymbol_value (sym);
>> +         if (pd->jvt_section != NULL
>> +             && jvt_base == bfd_section_vma (pd->jvt_section))
>> +           pd->has_jvt_base = true;
>> +       }
>>       }
>>
>>     pd->xlen = 0;
>> +  riscv_set_xlen_from_elf (pd, info);
>>     pd->default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
>>     pd->default_priv_spec = PRIV_SPEC_CLASS_NONE;
>>
>> @@ -1598,8 +1718,21 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
>>     ((struct riscv_private_data *) info->private_data)->last_map_state = mstate;
>>
>>     /* Set the size to dump.  */
>> -  if (mstate == MAP_DATA
>> -      && (info->flags & DISASSEMBLE_DATA) == 0)
>> +  if (info->section != NULL
>> +      && strcmp (info->section->name, TABLE_JUMP_SEC_NAME) == 0)
>> +    {
>> +      struct riscv_private_data *pd = info->private_data;
>> +      riscv_set_xlen_from_elf (pd, info);
>> +
>> +      dump_size = pd->xlen / 8;
>> +      info->bytes_per_chunk = dump_size;
>> +      info->bytes_per_line = dump_size;
>> +      info->endian_code = bfd_big_endian (info->section->owner)
>> +                          ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
>> +      info->display_endian = info->endian_code;
>> +      riscv_disassembler = riscv_disassemble_jvt;
>> +    }
>> +  else if (mstate == MAP_DATA && (info->flags & DISASSEMBLE_DATA) == 0)
>>       {
>>         dump_size = riscv_data_length (memaddr, info);
>>         info->bytes_per_chunk = dump_size;
>> @@ -1829,5 +1962,6 @@ void disassemble_free_riscv (struct disassemble_info *info ATTRIBUTE_UNUSED)
>>       {
>>         riscv_release_subset_list (pd->riscv_rps_dis.subset_list);
>>         free (pd->riscv_rps_dis.subset_list);
>> +      free (pd->jvt_content);
>>       }
>>   }
>> --
>> 2.43.0
>>



More information about the Binutils mailing list