[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