[RFC PATCH 5/5] RISC-V: Add Zcmt table-jump linker tests
Jiawei
jiawei@iscas.ac.cn
Sat Jun 27 10:45:55 GMT 2026
This patch adds zcmt table jump relaxation tests.
Cover opt-in behavior, profitability, RV32/RV64 table emission,
no-benefit and no-Zcmt cases, PIC/shared negative behavior,
section layout, symbol policy, addends, GC, overflow,
and the Zcd encoding conflict.
ld/ChangeLog:
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add Zcmt tests.
* testsuite/ld-riscv-elf/table-jump-addend.d: New test.
* testsuite/ld-riscv-elf/table-jump-addend.s: New test.
* testsuite/ld-riscv-elf/table-jump-base-collision.d: New test.
* testsuite/ld-riscv-elf/table-jump-base-collision.s: New test.
* testsuite/ld-riscv-elf/table-jump-base-local-collision.d: New test.
* testsuite/ld-riscv-elf/table-jump-base-local-collision.s: New test.
* testsuite/ld-riscv-elf/table-jump-be32-bytes.d: New test.
* testsuite/ld-riscv-elf/table-jump-be32-text.d: New test.
* testsuite/ld-riscv-elf/table-jump-be64-bytes.d: New test.
* testsuite/ld-riscv-elf/table-jump-be64-text.d: New test.
* testsuite/ld-riscv-elf/table-jump-benefit.d: New test.
* testsuite/ld-riscv-elf/table-jump-benefit.s: New test.
* testsuite/ld-riscv-elf/table-jump-default-jvt-relocs.d: New test.
* testsuite/ld-riscv-elf/table-jump-default-jvt-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-default-jvt.d: New test.
* testsuite/ld-riscv-elf/table-jump-default-no-jvt.d: New test.
* testsuite/ld-riscv-elf/table-jump-dump-unknown.d: New test.
* testsuite/ld-riscv-elf/table-jump-emit-relocs.d: New test.
* testsuite/ld-riscv-elf/table-jump-equal-benefit.d: New test.
* testsuite/ld-riscv-elf/table-jump-equal-benefit.s: New test.
* testsuite/ld-riscv-elf/table-jump-gc-comdat-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-gc-comdat.d: New test.
* testsuite/ld-riscv-elf/table-jump-gc-comdat.s: New test.
* testsuite/ld-riscv-elf/table-jump-gc-dead-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-gc-dead.d: New test.
* testsuite/ld-riscv-elf/table-jump-gc-dead.s: New test.
* testsuite/ld-riscv-elf/table-jump-jalt.d: New test.
* testsuite/ld-riscv-elf/table-jump-jt.d: New test.
* testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s: New test.
* testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d: New test.
* testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s: New test.
* testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.s: New test.
* testsuite/ld-riscv-elf/table-jump-no-benefit-section.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-benefit-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-benefit.s: New test.
* testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-relo-1.s: New test.
* testsuite/ld-riscv-elf/table-jump-no-relo-2.s: New test.
* testsuite/ld-riscv-elf/table-jump-no-relo.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-zcmt.d: New test.
* testsuite/ld-riscv-elf/table-jump-no-zcmt.s: New test.
* testsuite/ld-riscv-elf/table-jump-norelax.d: New test.
* testsuite/ld-riscv-elf/table-jump-norelax.s: New test.
* testsuite/ld-riscv-elf/table-jump-overflow.d: New test.
* testsuite/ld-riscv-elf/table-jump-overflow.s: New test.
* testsuite/ld-riscv-elf/table-jump-pie-relocs.d: New test.
* testsuite/ld-riscv-elf/table-jump-pie-text.d: New test.
* testsuite/ld-riscv-elf/table-jump-pie.d: New test.
* testsuite/ld-riscv-elf/table-jump-pie.s: New test.
* testsuite/ld-riscv-elf/table-jump-relax-zcmt.d: New test.
* testsuite/ld-riscv-elf/table-jump-rv32.d: New test.
* testsuite/ld-riscv-elf/table-jump-rv32.s: New test.
* testsuite/ld-riscv-elf/table-jump-shared-relocs.d: New test.
* testsuite/ld-riscv-elf/table-jump-shared-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-shared-text.d: New test.
* testsuite/ld-riscv-elf/table-jump-shared.d: New test.
* testsuite/ld-riscv-elf/table-jump-shared.s: New test.
* testsuite/ld-riscv-elf/table-jump-strip-symbol.d: New test.
* testsuite/ld-riscv-elf/table-jump-symbol-policy.d: New test.
* testsuite/ld-riscv-elf/table-jump-vma-lma.d: New test.
* testsuite/ld-riscv-elf/table-jump-vma-lma.ld: New test.
* testsuite/ld-riscv-elf/table-jump-vma-zero.d: New test.
* testsuite/ld-riscv-elf/table-jump-vma-zero.ld: New test.
* testsuite/ld-riscv-elf/table-jump-vma-zero.s: New test.
* testsuite/ld-riscv-elf/table-jump-zcd-conflict.d: New test.
* testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.d: New test.
* testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.s: New test.
* testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.d: New test.
* testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.s: New test.
* testsuite/ld-riscv-elf/table-jump.ld: New test.
* testsuite/ld-riscv-elf/table-jump.s: New test.
---
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 50 ++++++++++++++++++
ld/testsuite/ld-riscv-elf/table-jump-addend.d | 18 +++++++
ld/testsuite/ld-riscv-elf/table-jump-addend.s | 21 ++++++++
.../ld-riscv-elf/table-jump-base-collision.d | 4 ++
.../ld-riscv-elf/table-jump-base-collision.s | 18 +++++++
.../table-jump-base-local-collision.d | 4 ++
.../table-jump-base-local-collision.s | 17 +++++++
.../ld-riscv-elf/table-jump-be32-bytes.d | 10 ++++
.../ld-riscv-elf/table-jump-be32-text.d | 13 +++++
.../ld-riscv-elf/table-jump-be64-bytes.d | 10 ++++
.../ld-riscv-elf/table-jump-be64-text.d | 13 +++++
.../ld-riscv-elf/table-jump-benefit.d | 17 +++++++
.../ld-riscv-elf/table-jump-benefit.s | 51 +++++++++++++++++++
.../table-jump-default-jvt-relocs.d | 9 ++++
.../table-jump-default-jvt-symbol.d | 10 ++++
.../ld-riscv-elf/table-jump-default-jvt.d | 12 +++++
.../ld-riscv-elf/table-jump-default-no-jvt.d | 15 ++++++
.../ld-riscv-elf/table-jump-dump-unknown.d | 25 +++++++++
.../ld-riscv-elf/table-jump-emit-relocs.d | 9 ++++
.../ld-riscv-elf/table-jump-equal-benefit.d | 18 +++++++
.../ld-riscv-elf/table-jump-equal-benefit.s | 19 +++++++
.../table-jump-gc-comdat-symbol.d | 9 ++++
.../ld-riscv-elf/table-jump-gc-comdat.d | 11 ++++
.../ld-riscv-elf/table-jump-gc-comdat.s | 18 +++++++
.../ld-riscv-elf/table-jump-gc-dead-symbol.d | 9 ++++
.../ld-riscv-elf/table-jump-gc-dead.d | 11 ++++
.../ld-riscv-elf/table-jump-gc-dead.s | 18 +++++++
ld/testsuite/ld-riscv-elf/table-jump-jalt.d | 18 +++++++
ld/testsuite/ld-riscv-elf/table-jump-jt.d | 23 +++++++++
.../table-jump-multiple-local-sym-2.s | 12 +++++
.../table-jump-multiple-local-sym.d | 16 ++++++
.../table-jump-multiple-local-sym.s | 18 +++++++
.../table-jump-no-benefit-jvt-ref.d | 4 ++
.../table-jump-no-benefit-jvt-ref.s | 16 ++++++
.../table-jump-no-benefit-section.d | 9 ++++
.../table-jump-no-benefit-symbol.d | 9 ++++
.../ld-riscv-elf/table-jump-no-benefit.s | 12 +++++
.../ld-riscv-elf/table-jump-no-relax-zcmt.d | 17 +++++++
.../ld-riscv-elf/table-jump-no-relo-1.s | 7 +++
.../ld-riscv-elf/table-jump-no-relo-2.s | 12 +++++
.../ld-riscv-elf/table-jump-no-relo.d | 16 ++++++
.../ld-riscv-elf/table-jump-no-zcmt.d | 16 ++++++
.../ld-riscv-elf/table-jump-no-zcmt.s | 16 ++++++
.../ld-riscv-elf/table-jump-norelax.d | 15 ++++++
.../ld-riscv-elf/table-jump-norelax.s | 17 +++++++
.../ld-riscv-elf/table-jump-overflow.d | 11 ++++
.../ld-riscv-elf/table-jump-overflow.s | 49 ++++++++++++++++++
.../ld-riscv-elf/table-jump-pie-relocs.d | 9 ++++
.../ld-riscv-elf/table-jump-pie-text.d | 9 ++++
ld/testsuite/ld-riscv-elf/table-jump-pie.d | 9 ++++
ld/testsuite/ld-riscv-elf/table-jump-pie.s | 13 +++++
.../ld-riscv-elf/table-jump-relax-zcmt.d | 23 +++++++++
ld/testsuite/ld-riscv-elf/table-jump-rv32.d | 15 ++++++
ld/testsuite/ld-riscv-elf/table-jump-rv32.s | 25 +++++++++
.../ld-riscv-elf/table-jump-shared-relocs.d | 9 ++++
.../ld-riscv-elf/table-jump-shared-symbol.d | 9 ++++
.../ld-riscv-elf/table-jump-shared-text.d | 9 ++++
ld/testsuite/ld-riscv-elf/table-jump-shared.d | 12 +++++
ld/testsuite/ld-riscv-elf/table-jump-shared.s | 15 ++++++
.../ld-riscv-elf/table-jump-strip-symbol.d | 9 ++++
.../ld-riscv-elf/table-jump-symbol-policy.d | 8 +++
.../ld-riscv-elf/table-jump-vma-lma.d | 16 ++++++
.../ld-riscv-elf/table-jump-vma-lma.ld | 10 ++++
.../ld-riscv-elf/table-jump-vma-zero.d | 15 ++++++
.../ld-riscv-elf/table-jump-vma-zero.ld | 13 +++++
.../ld-riscv-elf/table-jump-vma-zero.s | 14 +++++
.../ld-riscv-elf/table-jump-zcd-conflict.d | 9 ++++
.../ld-riscv-elf/table-jump-zcmt-no-zca.d | 9 ++++
.../ld-riscv-elf/table-jump-zcmt-no-zca.s | 24 +++++++++
.../ld-riscv-elf/table-jump-zcmt-no-zicsr.d | 9 ++++
.../ld-riscv-elf/table-jump-zcmt-no-zicsr.s | 24 +++++++++
ld/testsuite/ld-riscv-elf/table-jump.ld | 16 ++++++
ld/testsuite/ld-riscv-elf/table-jump.s | 46 +++++++++++++++++
73 files changed, 1131 insertions(+)
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-addend.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-addend.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-base-collision.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-base-collision.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-be32-bytes.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-be32-text.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-be64-bytes.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-be64-text.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-benefit.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-benefit.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-default-jvt-relocs.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-default-jvt-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-default-jvt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-default-no-jvt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-emit-relocs.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-comdat-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-dead-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-dead.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-gc-dead.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-jalt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-jt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-benefit-section.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-benefit-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-benefit.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-norelax.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-norelax.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-overflow.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-overflow.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-pie-relocs.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-pie-text.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-pie.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-pie.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-rv32.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-rv32.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared-relocs.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared-text.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-strip-symbol.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-symbol-policy.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-vma-lma.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-vma-lma.ld
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-vma-zero.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-vma-zero.ld
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-vma-zero.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-zcd-conflict.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.d
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.s
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump.ld
create mode 100644 ld/testsuite/ld-riscv-elf/table-jump.s
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 8e26ccff10a..32f953aba78 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -182,11 +182,60 @@ if [istarget "riscv*-*-*"] {
"-march=rv64i -mabi=lp64" {weakref64.s} \
{{objdump -d weakref64.d}} "weakref64"]]
+ # Zcmt (jump table) tests.
+ run_dump_test "table-jump-jalt"
+ run_dump_test "table-jump-jt"
+ run_dump_test "table-jump-dump-unknown"
+ run_dump_test "table-jump-no-relo"
+ run_dump_test "table-jump-relax-zcmt"
+ run_dump_test "table-jump-no-relax-zcmt"
+ run_dump_test "table-jump-multiple-local-sym"
+ run_dump_test "table-jump-benefit"
+ run_dump_test "table-jump-addend"
+ run_dump_test "table-jump-norelax"
+ run_dump_test "table-jump-no-zcmt"
+ run_dump_test "table-jump-zcmt-no-zca"
+ run_dump_test "table-jump-zcmt-no-zicsr"
+ run_dump_test "table-jump-zcd-conflict"
+ run_dump_test "table-jump-overflow"
+ run_dump_test "table-jump-equal-benefit"
+ run_dump_test "table-jump-rv32"
+ run_dump_test "table-jump-vma-zero"
+ run_dump_test "table-jump-emit-relocs"
+ run_dump_test "table-jump-be64-bytes"
+ run_dump_test "table-jump-be64-text"
+ run_dump_test "table-jump-be32-bytes"
+ run_dump_test "table-jump-be32-text"
+ run_dump_test "table-jump-no-benefit-symbol"
+ run_dump_test "table-jump-no-benefit-section"
+ run_dump_test "table-jump-no-benefit-jvt-ref"
+ run_dump_test "table-jump-default-no-jvt"
+ run_dump_test "table-jump-default-jvt"
+ run_dump_test "table-jump-default-jvt-symbol"
+ run_dump_test "table-jump-default-jvt-relocs"
+ run_dump_test "table-jump-base-collision"
+ run_dump_test "table-jump-base-local-collision"
+ run_dump_test "table-jump-symbol-policy"
+ run_dump_test "table-jump-strip-symbol"
+ run_dump_test "table-jump-gc-dead"
+ run_dump_test "table-jump-gc-dead-symbol"
+ run_dump_test "table-jump-gc-comdat"
+ run_dump_test "table-jump-gc-comdat-symbol"
+ run_dump_test "table-jump-vma-lma"
+
# The following tests require shared library support.
if ![check_shared_lib_support] {
return
}
+ run_dump_test "table-jump-pie"
+ run_dump_test "table-jump-pie-text"
+ run_dump_test "table-jump-pie-relocs"
+ run_dump_test "table-jump-shared"
+ run_dump_test "table-jump-shared-text"
+ run_dump_test "table-jump-shared-symbol"
+ run_dump_test "table-jump-shared-relocs"
+
run_dump_test "relro-relax-lui"
run_dump_test "relro-relax-pcrel"
run_dump_test "variant_cc-now"
@@ -342,4 +391,5 @@ if [istarget "riscv*-*-*"] {
run_dump_test "tls"
run_dump_test "tlsbin"
run_dump_test "absolute-no-relative"
+
}
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-addend.d b/ld/testsuite/ld-riscv-elf/table-jump-addend.d
new file mode 100644
index 00000000000..11cc2b9fdfe
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-addend.d
@@ -0,0 +1,18 @@
+#source: table-jump-addend.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+target
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[33\]:[ ]+target_4
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[34\]:[ ]+target_8
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <target>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+33 # [0-9a-f]+ <target_4>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+34 # [0-9a-f]+ <target_8>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-addend.s b/ld/testsuite/ld-riscv-elf/table-jump-addend.s
new file mode 100644
index 00000000000..823e0710e08
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-addend.s
@@ -0,0 +1,21 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 50
+ call target
+ call target + 4
+ call target + 8
+ .endr
+
+ .globl target
+ .type target, %function
+target:
+ .word 0x00000013
+ .globl target_4
+target_4:
+ .word 0x00000013
+ .globl target_8
+target_8:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-base-collision.d b/ld/testsuite/ld-riscv-elf/table-jump-base-collision.d
new file mode 100644
index 00000000000..5cdfe8a8e77
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-base-collision.d
@@ -0,0 +1,4 @@
+#source: table-jump-base-collision.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#error: .*__jvt_base\$ is reserved for Zcmt table-jump relaxation
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-base-collision.s b/ld/testsuite/ld-riscv-elf/table-jump-base-collision.s
new file mode 100644
index 00000000000..182150f86a5
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-base-collision.s
@@ -0,0 +1,18 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 5
+ tail target
+ .endr
+ ret
+ .space 4096
+
+ .globl __jvt_base$
+__jvt_base$:
+ .word 0
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.d b/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.d
new file mode 100644
index 00000000000..2708f2e86d1
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.d
@@ -0,0 +1,4 @@
+#source: table-jump-base-local-collision.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#error: .*__jvt_base\$ is reserved for Zcmt table-jump relaxation
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.s b/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.s
new file mode 100644
index 00000000000..f7206d15b49
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-base-local-collision.s
@@ -0,0 +1,17 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 5
+ tail target
+ .endr
+ ret
+ .space 4096
+
+__jvt_base$:
+ .word 0
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-be32-bytes.d b/ld/testsuite/ld-riscv-elf/table-jump-be32-bytes.d
new file mode 100644
index 00000000000..49dc3451e16
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-be32-bytes.d
@@ -0,0 +1,10 @@
+#source: table-jump-rv32.s
+#as: -march=rv32ic_zcmt -mbig-endian
+#ld: -melf32briscv -Ttable-jump.ld --relax-zcmt
+#objdump: -s -j .riscv.jvt
+
+#...
+.*: file format elf32-bigriscv
+#...
+Contents of section .riscv.jvt:
+[ ]+0+[0-9a-f]*[ ]+0000400e[ ]+0000400c.*
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-be32-text.d b/ld/testsuite/ld-riscv-elf/table-jump-be32-text.d
new file mode 100644
index 00000000000..a7a00bf3e39
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-be32-text.d
@@ -0,0 +1,13 @@
+#source: table-jump-rv32.s
+#as: -march=rv32ic_zcmt -mbig-endian
+#ld: -melf32briscv -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+
+#...
+.*: file format elf32-bigriscv
+#...
+Disassembly of section .text:
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-be64-bytes.d b/ld/testsuite/ld-riscv-elf/table-jump-be64-bytes.d
new file mode 100644
index 00000000000..7dbc2d1a30e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-be64-bytes.d
@@ -0,0 +1,10 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1 -mbig-endian
+#ld: -melf64briscv -Ttable-jump.ld --relax-zcmt
+#objdump: -s -j .riscv.jvt
+
+#...
+.*: file format elf64-bigriscv
+#...
+Contents of section .riscv.jvt:
+[ ]+0+[0-9a-f]*[ ]+00000000[ ]+00004016[ ]+00000000[ ]+00004014.*
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-be64-text.d b/ld/testsuite/ld-riscv-elf/table-jump-be64-text.d
new file mode 100644
index 00000000000..7477201f199
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-be64-text.d
@@ -0,0 +1,13 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1 -mbig-endian
+#ld: -melf64briscv -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+
+#...
+.*: file format elf64-bigriscv
+#...
+Disassembly of section .text:
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-benefit.d b/ld/testsuite/ld-riscv-elf/table-jump-benefit.d
new file mode 100644
index 00000000000..2fe5c787605
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-benefit.d
@@ -0,0 +1,17 @@
+#source: table-jump-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+func_d
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[33\]:[ ]+func_c
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[34\]:[ ]+func_b
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[35\]:[ ]+func_a
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <func_d>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-benefit.s b/ld/testsuite/ld-riscv-elf/table-jump-benefit.s
new file mode 100644
index 00000000000..0450fef000f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-benefit.s
@@ -0,0 +1,51 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ # Test benefit ranking: higher frequency functions should
+ # be prioritized for JVT entry allocation.
+ # Use reverse alphabetical order to verify sorting by benefit,
+ # not by name.
+
+ # func_d called 80 times - highest benefit
+ .rept 80
+ call func_d
+ .endr
+
+ # func_c called 50 times - medium benefit
+ .rept 50
+ call func_c
+ .endr
+
+ # func_b called 20 times - lower benefit
+ .rept 20
+ call func_b
+ .endr
+
+ # func_a called 5 times - lowest benefit
+ .rept 5
+ call func_a
+ .endr
+
+ ret
+
+ .globl func_a
+ .type func_a, %function
+func_a:
+ ret
+
+ .globl func_b
+ .type func_b, %function
+func_b:
+ ret
+
+ .globl func_c
+ .type func_c, %function
+func_c:
+ ret
+
+ .globl func_d
+ .type func_d, %function
+func_d:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-relocs.d b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-relocs.d
new file mode 100644
index 00000000000..9b3079f24b3
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-relocs.d
@@ -0,0 +1,9 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: --relax-zcmt
+#readelf: -rW
+
+#failif
+#...
+.*R_RISCV_TABLE_JUMP.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-symbol.d
new file mode 100644
index 00000000000..5dd5e43c680
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt-symbol.d
@@ -0,0 +1,10 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: --relax-zcmt
+#readelf: -SWs
+
+#...
+.*\.riscv\.jvt[ ]+PROGBITS[ ]+[0-9a-f]+[ ]+[0-9a-f]+[ ]+[0-9a-f]+.*
+#...
+[ ]+[0-9]+:[ ]+0+[0-9a-f]+[ ]+0[ ]+NOTYPE[ ]+LOCAL[ ]+DEFAULT[ ]+[0-9]+[ ]+__jvt_base\$
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-default-jvt.d b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt.d
new file mode 100644
index 00000000000..96c9efaa29d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-default-jvt.d
@@ -0,0 +1,12 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .text:
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-default-no-jvt.d b/ld/testsuite/ld-riscv-elf/table-jump-default-no-jvt.d
new file mode 100644
index 00000000000..1ebad80ec12
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-default-no-jvt.d
@@ -0,0 +1,15 @@
+#source: table-jump-no-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <target>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <target>
+#...
+0+[0-9a-f]+ <target>:
+.*:[ ]+[0-9a-f]+[ ]+ret
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d b/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
new file mode 100644
index 00000000000..53e9097603c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
@@ -0,0 +1,25 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1
+#ld: -Ttable-jump.ld --strip-all --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <.riscv.jvt>:
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[0\]:[ ]+<unknown>
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[1\]:[ ]+<unknown>
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <.text>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1
+#...
+.*:[ ]+[0-9a-f]+[ ]+ret
+.*:[ ]+[0-9a-f]+[ ]+ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-emit-relocs.d b/ld/testsuite/ld-riscv-elf/table-jump-emit-relocs.d
new file mode 100644
index 00000000000..32c69c727ae
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-emit-relocs.d
@@ -0,0 +1,9 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump.ld --emit-relocs --relax-zcmt
+#readelf: -rW
+
+#failif
+#...
+.*R_RISCV_(TABLE_JUMP|DELETE|DELETE_AND_RELAX).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.d b/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.d
new file mode 100644
index 00000000000..6f4ed2e2682
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.d
@@ -0,0 +1,18 @@
+#source: table-jump-equal-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+func_b
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[33\]:[ ]+func_a
+#...
+Disassembly of section .text:
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <func_b>
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+33 # [0-9a-f]+ <func_a>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.s b/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.s
new file mode 100644
index 00000000000..13dc4200569
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-equal-benefit.s
@@ -0,0 +1,19 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 70
+ call func_b
+ call func_a
+ .endr
+
+ .globl func_a
+ .type func_a, %function
+func_a:
+ ret
+
+ .globl func_b
+ .type func_b, %function
+func_b:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat-symbol.d
new file mode 100644
index 00000000000..0b8ebee90bc
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat-symbol.d
@@ -0,0 +1,9 @@
+#source: table-jump-gc-comdat.s
+#as: -march=rv64ic_zcmt
+#ld: --gc-sections --relax-zcmt -e _start
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.d b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.d
new file mode 100644
index 00000000000..6a5e01c8ae9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.d
@@ -0,0 +1,11 @@
+#source: table-jump-gc-comdat.s
+#as: -march=rv64ic_zcmt
+#ld: --gc-sections --relax-zcmt -e _start
+#objdump: -d
+
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+ret
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.s b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.s
new file mode 100644
index 00000000000..591d7c47e29
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-comdat.s
@@ -0,0 +1,18 @@
+ .section .text.live, "ax"
+
+ .globl _start
+ .type _start, %function
+_start:
+ ret
+
+ .section .text.dead_group, "axG", @progbits, dead_group, comdat
+ .type dead_group_start, %function
+dead_group_start:
+ .rept 70
+ call dead_group_target
+ .endr
+ ret
+
+ .type dead_group_target, %function
+dead_group_target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-dead-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead-symbol.d
new file mode 100644
index 00000000000..b8a14241f12
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead-symbol.d
@@ -0,0 +1,9 @@
+#source: table-jump-gc-dead.s
+#as: -march=rv64ic_zcmt
+#ld: --gc-sections --relax-zcmt -e _start
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.d b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.d
new file mode 100644
index 00000000000..1c95f06c7e0
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.d
@@ -0,0 +1,11 @@
+#source: table-jump-gc-dead.s
+#as: -march=rv64ic_zcmt
+#ld: --gc-sections --relax-zcmt -e _start
+#objdump: -d
+
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+ret
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.s b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.s
new file mode 100644
index 00000000000..0030a207897
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-gc-dead.s
@@ -0,0 +1,18 @@
+ .section .text.live, "ax"
+
+ .globl _start
+ .type _start, %function
+_start:
+ ret
+
+ .section .text.dead, "ax"
+ .type dead_start, %function
+dead_start:
+ .rept 70
+ call dead_target
+ .endr
+ ret
+
+ .type dead_target, %function
+dead_target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-jalt.d b/ld/testsuite/ld-riscv-elf/table-jump-jalt.d
new file mode 100644
index 00000000000..098e65fc403
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-jalt.d
@@ -0,0 +1,18 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+foo_global
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[33\]:[ ]+foo_local
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+33 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+33 # [0-9a-f]+ <foo_local>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-jt.d b/ld/testsuite/ld-riscv-elf/table-jump-jt.d
new file mode 100644
index 00000000000..0b0250ee104
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-jt.d
@@ -0,0 +1,23 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[0\]:[ ]+foo_local
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[1\]:[ ]+foo_global
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
new file mode 100644
index 00000000000..bf106b88f2d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
@@ -0,0 +1,12 @@
+ .section .text
+ .type bar, %function
+bar:
+ .rept 70
+ call foo_local
+ call foo_global
+ .endr
+ ret
+
+ .type foo_local, %function
+foo_local:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
new file mode 100644
index 00000000000..07dbd3978be
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
@@ -0,0 +1,16 @@
+#source: table-jump-multiple-local-sym.s
+#source: table-jump-multiple-local-sym-2.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+foo_global
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[33\]:[ ]+foo_local
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[34\]:[ ]+foo_local
+
+Disassembly of section .text:
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
new file mode 100644
index 00000000000..ccc2525e2f7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
@@ -0,0 +1,18 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 70
+ call foo_global
+ call foo_local
+ .endr
+
+ .globl foo_global
+ .type foo_global, %function
+foo_global:
+ ret
+
+ .type foo_local, %function
+foo_local:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.d b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.d
new file mode 100644
index 00000000000..3b392efa45c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.d
@@ -0,0 +1,4 @@
+#source: table-jump-no-benefit-jvt-ref.s
+#as: -march=rv64ic_zcmt
+#ld: --relax-zcmt
+#error: .*undefined reference to `__jvt_base\$'
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.s b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.s
new file mode 100644
index 00000000000..3665215f92d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-jvt-ref.s
@@ -0,0 +1,16 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .option push
+ .option norelax
+ la a0, __jvt_base$
+ .option pop
+ tail target
+ tail target
+ .space 4096
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-section.d b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-section.d
new file mode 100644
index 00000000000..74363ad11c6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-section.d
@@ -0,0 +1,9 @@
+#source: table-jump-no-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: --relax-zcmt
+#readelf: -SW
+
+#failif
+#...
+.*\.riscv\.jvt.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-symbol.d
new file mode 100644
index 00000000000..6d5eb9a35b0
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit-symbol.d
@@ -0,0 +1,9 @@
+#source: table-jump-no-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: --relax-zcmt
+#readelf: -sW
+
+#failif
+#...
+.*__jvt_base\$.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-benefit.s b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit.s
new file mode 100644
index 00000000000..2292cc43b3e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-benefit.s
@@ -0,0 +1,12 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ tail target
+ tail target
+ .space 4096
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
new file mode 100644
index 00000000000..a551a05c97e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
@@ -0,0 +1,17 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: -Ttable-jump.ld --no-relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
new file mode 100644
index 00000000000..d3e9b7ce4dd
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
@@ -0,0 +1,7 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+L0: j L0
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
new file mode 100644
index 00000000000..f68cdaf423b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
@@ -0,0 +1,12 @@
+ .section .text
+
+ .globl foo
+ .type foo, %function
+foo:
+ call bar
+
+
+ .globl bar
+ .type bar, %function
+bar:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d b/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
new file mode 100644
index 00000000000..9ff45cb2616
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
@@ -0,0 +1,16 @@
+#source: table-jump-no-relo-1.s
+#source: table-jump-no-relo-2.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <_start>
+.*:[ ]+[0-9a-f]+[ ]+ret
+
+0+[0-9a-f]+ <foo>:
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <bar>
+
+0+[0-9a-f]+ <bar>:
+.*:[ ]+[0-9a-f]+[ ]+ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
new file mode 100644
index 00000000000..5b23e81e2c8
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
@@ -0,0 +1,16 @@
+#source: table-jump-no-zcmt.s
+#as: -march=rv64ic
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+# All calls should remain as jal (not converted to cm.jalt)
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <foo>
+#...
+0+[0-9a-f]+ <foo>:
+.*:[ ]+[0-9a-f]+[ ]+ret
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
new file mode 100644
index 00000000000..3e483757ba5
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
@@ -0,0 +1,16 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ # This file is assembled without Zcmt extension.
+ # The linker should NOT generate JVT section
+ .rept 50
+ call foo
+ .endr
+ ret
+
+ .globl foo
+ .type foo, %function
+foo:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-norelax.d b/ld/testsuite/ld-riscv-elf/table-jump-norelax.d
new file mode 100644
index 00000000000..8621ad8550b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-norelax.d
@@ -0,0 +1,15 @@
+#source: table-jump-norelax.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+ra,0x1
+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+[0-9]+\(ra\) # [0-9a-f]+ <target>
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+t[0-9],0x1
+.*:[ ]+[0-9a-f]+[ ]+jr[ ]+[0-9]+\(t[0-9]\) # [0-9a-f]+ <target>
+.*:[ ]+[0-9a-f]+[ ]+j[ ]+[0-9a-f]+ <target>
+#...
+0+[0-9a-f]+ <target>:
+.*:[ ]+[0-9a-f]+[ ]+ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-norelax.s b/ld/testsuite/ld-riscv-elf/table-jump-norelax.s
new file mode 100644
index 00000000000..0880f79a5c5
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-norelax.s
@@ -0,0 +1,17 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .option push
+ .option norelax
+ call target
+ tail target
+ jal x0, target
+ .option pop
+
+ .space 4096
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-overflow.d b/ld/testsuite/ld-riscv-elf/table-jump-overflow.d
new file mode 100644
index 00000000000..4b5e36005a9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-overflow.d
@@ -0,0 +1,11 @@
+#source: table-jump-overflow.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <func_top>
+#...
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <func_overflow>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-overflow.s b/ld/testsuite/ld-riscv-elf/table-jump-overflow.s
new file mode 100644
index 00000000000..5aae80f24c6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-overflow.s
@@ -0,0 +1,49 @@
+ .altmacro
+ .section .text
+
+ # Test JVT overflow: cm.jalt has 224 entries (index 32-255)
+ # func_top: called 10x (highest benefit), guaranteed jvt.jalt[32]
+ # func_0 to func_222: called 2x each, fill remaining 223 JVT slots
+ # func_overflow: called 1x (lowest benefit), overflows, remains jal
+
+ .macro call2 n
+ call func_\n
+ call func_\n
+ .endm
+
+ .macro defn n
+ .type func_\n, %function
+func_\n: ret
+ .endm
+
+ .globl _start
+ .type _start, %function
+_start:
+ # func_top: highest benefit, guaranteed first JVT entry
+ .rept 10
+ call func_top
+ .endr
+
+ # 223 functions with 2 calls each (fill remaining JVT entries)
+ .set i, 0
+ .rept 223
+ call2 %i
+ .set i, i+1
+ .endr
+
+ # func_overflow: lowest benefit, will not fit in JVT
+ call func_overflow
+ ret
+
+ # Define functions
+ .type func_top, %function
+func_top: ret
+
+ .set i, 0
+ .rept 223
+ defn %i
+ .set i, i+1
+ .endr
+
+ .type func_overflow, %function
+func_overflow: ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-pie-relocs.d b/ld/testsuite/ld-riscv-elf/table-jump-pie-relocs.d
new file mode 100644
index 00000000000..407acf5fcc6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-pie-relocs.d
@@ -0,0 +1,9 @@
+#source: table-jump-pie.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -pie --relax-zcmt
+#readelf: -rW
+
+#failif
+#...
+.*R_RISCV_(TABLE_JUMP|DELETE|DELETE_AND_RELAX).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-pie-text.d b/ld/testsuite/ld-riscv-elf/table-jump-pie-text.d
new file mode 100644
index 00000000000..8cb52d4a5df
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-pie-text.d
@@ -0,0 +1,9 @@
+#source: table-jump-pie.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -pie --relax-zcmt
+#objdump: -d
+
+#failif
+#...
+.*cm\.j(al)?t.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-pie.d b/ld/testsuite/ld-riscv-elf/table-jump-pie.d
new file mode 100644
index 00000000000..d8a8a6a532d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-pie.d
@@ -0,0 +1,9 @@
+#source: table-jump-pie.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -pie --relax-zcmt
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-pie.s b/ld/testsuite/ld-riscv-elf/table-jump-pie.s
new file mode 100644
index 00000000000..3d5fe7759bd
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-pie.s
@@ -0,0 +1,13 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 70
+ call target
+ .endr
+ ret
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
new file mode 100644
index 00000000000..1adb1b289ce
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
@@ -0,0 +1,23 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[0\]:[ ]+foo_global
+[ ]+...
+.*:[ ]+[0-9a-f]+[ ]+jvt.jalt\[32\]:[ ]+foo_global
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # [0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-rv32.d b/ld/testsuite/ld-riscv-elf/table-jump-rv32.d
new file mode 100644
index 00000000000..ef6bbcdd526
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-rv32.d
@@ -0,0 +1,15 @@
+#source: table-jump-rv32.s
+#as: -march=rv32ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt -melf32lriscv
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[0\]:[ ]+foo_local
+.*:[ ]+[0-9a-f]+[ ]+jvt.jt\[1\]:[ ]+foo_global
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # [0-9a-f]+ <foo_local>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+1 # [0-9a-f]+ <foo_global>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-rv32.s b/ld/testsuite/ld-riscv-elf/table-jump-rv32.s
new file mode 100644
index 00000000000..274c3b03f8b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-rv32.s
@@ -0,0 +1,25 @@
+ .section .text
+
+ # Test RV32 ZCMT relaxation for cm.jt
+ # jal x0 (no link) -> cm.jt (index 0-31)
+ # JVT entry cost: 4 bytes (RV32), benefit = 2 per call
+ # Threshold: 3*2=6 > 4 (just profitable)
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 3
+ tail foo_local
+ tail foo_global
+ .endr
+
+ .space 4096
+
+ .globl foo_global
+ .type foo_global, %function
+foo_global:
+ ret
+
+ .type foo_local, %function
+foo_local:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared-relocs.d b/ld/testsuite/ld-riscv-elf/table-jump-shared-relocs.d
new file mode 100644
index 00000000000..1c879fff883
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared-relocs.d
@@ -0,0 +1,9 @@
+#source: table-jump-shared.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -shared --relax-zcmt
+#readelf: -rW
+
+#failif
+#...
+.*R_RISCV_(TABLE_JUMP|DELETE|DELETE_AND_RELAX).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-shared-symbol.d
new file mode 100644
index 00000000000..a82763c2f8c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared-symbol.d
@@ -0,0 +1,9 @@
+#source: table-jump-shared.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -shared --relax-zcmt
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared-text.d b/ld/testsuite/ld-riscv-elf/table-jump-shared-text.d
new file mode 100644
index 00000000000..262d4c59643
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared-text.d
@@ -0,0 +1,9 @@
+#source: table-jump-shared.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -shared --relax-zcmt
+#objdump: -d
+
+#failif
+#...
+.*cm\.j(al)?t.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared.d b/ld/testsuite/ld-riscv-elf/table-jump-shared.d
new file mode 100644
index 00000000000..1fec141e6b6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared.d
@@ -0,0 +1,12 @@
+#source: table-jump-shared.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -shared --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <foo>:
+# Calls should NOT be cm.jalt in shared library (should be jal to PLT)
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <bar@plt>
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+[0-9a-f]+ <bar@plt>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared.s b/ld/testsuite/ld-riscv-elf/table-jump-shared.s
new file mode 100644
index 00000000000..0bd853d1ae6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared.s
@@ -0,0 +1,15 @@
+ .section .text
+
+ .globl foo
+ .type foo, %function
+foo:
+ # Shared library: JVT relaxation should be disabled
+ .rept 50
+ call bar
+ .endr
+ ret
+
+ .globl bar
+ .type bar, %function
+bar:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-strip-symbol.d b/ld/testsuite/ld-riscv-elf/table-jump-strip-symbol.d
new file mode 100644
index 00000000000..39b1d99e93e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-strip-symbol.d
@@ -0,0 +1,9 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump.ld --strip-all --relax-zcmt
+#readelf: -sW
+
+#failif
+#...
+.*__jvt_base\$.*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-symbol-policy.d b/ld/testsuite/ld-riscv-elf/table-jump-symbol-policy.d
new file mode 100644
index 00000000000..acd152a93be
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-symbol-policy.d
@@ -0,0 +1,8 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#readelf: -sW
+
+#...
+[ ]+[0-9]+:[ ]+0+[0-9a-f]+[ ]+0[ ]+NOTYPE[ ]+LOCAL[ ]+DEFAULT[ ]+[0-9]+[ ]+__jvt_base\$
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.d b/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.d
new file mode 100644
index 00000000000..222d546df8b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.d
@@ -0,0 +1,16 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump-vma-lma.ld --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .riscv.jvt:
+#...
+.*:[ ]+0000000000003118[ ]+jvt.jalt\[32\]:[ ]+foo_global
+.*:[ ]+000000000000311a[ ]+jvt.jalt\[33\]:[ ]+foo_local
+#...
+Disassembly of section .text:
+#...
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+32 # 3118 <foo_global>
+.*:[ ]+[0-9a-f]+[ ]+cm.jalt[ ]+33 # 311a <foo_local>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.ld b/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.ld
new file mode 100644
index 00000000000..a8202afb381
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-vma-lma.ld
@@ -0,0 +1,10 @@
+ENTRY(_start)
+SECTIONS
+{
+ .riscv.jvt 0x1000 : AT(0x8000) {
+ *(.riscv.jvt)
+ }
+ .text 0x3000 : AT(0x9000) {
+ *(.text)
+ }
+}
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.d b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.d
new file mode 100644
index 00000000000..c93a1c6c4f2
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.d
@@ -0,0 +1,15 @@
+#source: table-jump-vma-zero.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump-vma-zero.ld --relax-zcmt
+#objdump: -d -s -j .riscv.jvt -j .text
+
+#...
+Contents of section .riscv.jvt:
+[ ]+1000[ ]+00000000[ ]+00000000.*
+#...
+Disassembly of section .text:
+#...
+0+3000 <_start>:
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # 0 <target>
+.*:[ ]+[0-9a-f]+[ ]+cm.jt[ ]+0 # 0 <target>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.ld b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.ld
new file mode 100644
index 00000000000..6db8ac52006
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.ld
@@ -0,0 +1,13 @@
+ENTRY(_start)
+SECTIONS
+{
+ .text.target 0x0 : {
+ *(.text.target)
+ }
+ .riscv.jvt 0x1000 : {
+ *(.riscv.jvt)
+ }
+ .text 0x3000 : {
+ *(.text.start)
+ }
+}
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.s b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.s
new file mode 100644
index 00000000000..742a0ee23fe
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-vma-zero.s
@@ -0,0 +1,14 @@
+ .section .text.start, "ax"
+
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 5
+ tail target
+ .endr
+ ret
+
+ .section .text.target, "ax"
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-zcd-conflict.d b/ld/testsuite/ld-riscv-elf/table-jump-zcd-conflict.d
new file mode 100644
index 00000000000..ed70f3fd94e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-zcd-conflict.d
@@ -0,0 +1,9 @@
+#source: table-jump.s
+#as: -march=rv64imafd_zicsr_zifencei_zca_zcd_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.d b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.d
new file mode 100644
index 00000000000..9554df1aa91
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.d
@@ -0,0 +1,9 @@
+#source: table-jump-zcmt-no-zca.s
+#as: -march=rv64i -mno-arch-attr
+#ld: --relax-zcmt
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.s b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.s
new file mode 100644
index 00000000000..91aa8f07ed3
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zca.s
@@ -0,0 +1,24 @@
+ .section .riscv.attributes,"",@0x70000003
+ .byte 0x41
+0:
+ .4byte 1f-0b
+ .asciz "riscv"
+2:
+ .byte 1
+ .4byte 1f-2b
+ .byte 5
+ .asciz "rv64i2p1_zicsr2p0_zcmt1p0"
+1:
+
+ .section .text
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 70
+ call target
+ .endr
+ ret
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.d b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.d
new file mode 100644
index 00000000000..981e5933097
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.d
@@ -0,0 +1,9 @@
+#source: table-jump-zcmt-no-zicsr.s
+#as: -march=rv64i -mno-arch-attr
+#ld: --relax-zcmt
+#readelf: -SWs
+
+#failif
+#...
+.*(__jvt_base\$|\.riscv\.jvt).*
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.s b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.s
new file mode 100644
index 00000000000..768a6fb32fa
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-zcmt-no-zicsr.s
@@ -0,0 +1,24 @@
+ .section .riscv.attributes,"",@0x70000003
+ .byte 0x41
+0:
+ .4byte 1f-0b
+ .asciz "riscv"
+2:
+ .byte 1
+ .4byte 1f-2b
+ .byte 5
+ .asciz "rv64i2p1_zca1p0_zcmt1p0"
+1:
+
+ .section .text
+ .globl _start
+ .type _start, %function
+_start:
+ .rept 70
+ call target
+ .endr
+ ret
+
+ .type target, %function
+target:
+ ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump.ld b/ld/testsuite/ld-riscv-elf/table-jump.ld
new file mode 100644
index 00000000000..ab84fdcb772
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump.ld
@@ -0,0 +1,16 @@
+ENTRY(_start)
+SECTIONS
+{
+ .got 0x1000 : {
+ *(.got)
+ }
+ .riscv.jvt : {
+ *(.riscv.jvt)
+ }
+ .data 0x2000: {
+ *(.data)
+ }
+ .text 0x3000 : {
+ *(.text)
+ }
+}
diff --git a/ld/testsuite/ld-riscv-elf/table-jump.s b/ld/testsuite/ld-riscv-elf/table-jump.s
new file mode 100644
index 00000000000..75574a69223
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump.s
@@ -0,0 +1,46 @@
+ .section .text
+
+ .globl _start
+ .type _start, %function
+_start:
+.ifdef TEST_CM_JT
+ .rept 5
+ tail foo_local
+ tail foo_global
+ .endr
+.endif
+
+.ifdef TEST_CM_JALT
+ .rept 70
+ call foo_global
+ call foo_local
+ .endr
+.endif
+
+.ifdef TEST_CM_JT_JALT
+ .rept 5
+ tail foo_global
+ .endr
+ .rept 140
+ call foo_global
+ .endr
+.endif
+
+ # Keep paired JAL candidates out of C.J range. Zcmt profiling runs
+ # after ordinary shortening, so near paired JALs should become C.J
+ # and no longer be Zcmt candidates.
+.ifdef TEST_CM_JT
+ .space 4096
+.endif
+.ifdef TEST_CM_JT_JALT
+ .space 4096
+.endif
+
+ .globl foo_global
+ .type foo_global, %function
+foo_global:
+ ret
+
+ .type foo_local, %function
+foo_local:
+ ret
--
2.43.0
More information about the Binutils
mailing list