[PATCH v1]RISC-V: Zcmt relaxationi support.
Umesh Kalappa
ukalappa.mips@gmail.com
Wed Dec 3 08:47:23 GMT 2025
Hi Everyone ,
Are the below changes good to commit ?
Thank you ,Good Day
~U
On Thu, Nov 27, 2025 at 10:35 AM Umesh Kalappa <ukalappa.mips@gmail.com>
wrote:
> 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/20251203/183116ca/attachment-0001.htm>
More information about the Binutils
mailing list