[PATCH v1]RISC-V: Zcmt relaxationi support.
Umesh Kalappa
ukalappa.mips@gmail.com
Thu Nov 27 05:05:55 GMT 2025
Thank you @jiawei <jiawei@iscas.ac.cn> and @Jeff Law
<jeffreyalaw@gmail.com> @Kito Cheng <kito.cheng@gmail.com> and others .
Please spare some mins to pass your suggestions / comments on the changes .
Thank you again,Good Day
~U
On Thu, Nov 27, 2025 at 8:23 AM Jiawei <jiawei@iscas.ac.cn> wrote:
> 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. */
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20251127/211ba247/attachment-0001.htm>
More information about the Binutils
mailing list