RISCV-V: Add new relocation type for global array accesses with non-constant indices

Message ID 9a0510003f0a97ceb31679b11655bd575a07234a.94f962d0.b746.443d.8f93.64a2c9b7c1e5@feishu.cn
State New
Headers
Series RISCV-V: Add new relocation type for global array accesses with non-constant indices |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

翁丽琴 March 24, 2026, 9:44 a.m. UTC
  This patch introduces support for new RISC-V relocation types (R_RISCV_REGREL_*) 
to enable more efficient code generation for global array accesses with non-constant 
array subscripts.

Changes:
- Add four new relocation types: R_RISCV_REGREL_LO12_I, R_RISCV_REGREL_LO12_S, 
  R_RISCV_REGREL_ADD, and R_RISCV_REGREL_SHXADD
- Update bfd, gas, and include modules with relocation support
- Add corresponding test cases

This implementation follows the RISC-V PSABI specification:
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/489

---

From ff29e254b34aa2ce6a012c49f98b04bac2e20d8d Mon Sep 17 00:00:00 2001
From: wengliqin <liqin.weng@spacemit.com>
Date: Tue, 24 Mar 2026 15:46:11 +0800
Subject: [PATCH] RISCV-V: Add new relocation type for global array accesses
 with non-constant indices.

Relocation Type Includes: R_RISCV_REGREL_ADD/R_RISCV_REGREL_SHXADD/R_RISCV_REGREL_LO12_I/R_RISCV_REGREL_LO12_S

psabi link: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/489
---
 bfd/ChangeLog                           |  14 +++
 bfd/bfd-in2.h                           |   8 +-
 bfd/elfnn-riscv.c                       |  64 +++++++++++-
 bfd/elfxx-riscv.c                       | 126 +++++++++++++++++++++++-
 bfd/libbfd.h                            |   4 +
 bfd/reloc.c                             |   8 ++
 gas/ChangeLog                           |  10 ++
 gas/config/tc-riscv.c                   |  43 ++++++--
 gas/testsuite/gas/riscv/regrel-add.d    |   3 +
 gas/testsuite/gas/riscv/regrel-add.l    |   3 +
 gas/testsuite/gas/riscv/regrel-add.s    |  12 +++
 gas/testsuite/gas/riscv/regrel-shxadd.d |   3 +
 gas/testsuite/gas/riscv/regrel-shxadd.l |   9 ++
 gas/testsuite/gas/riscv/regrel-shxadd.s |  18 ++++
 include/ChangeLog                       |   4 +
 include/elf/riscv.h                     |  12 +++
 opcodes/ChangeLog                       |   4 +
 opcodes/riscv-opc.c                     |  19 ++--
 18 files changed, 347 insertions(+), 17 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/regrel-add.d
 create mode 100644 gas/testsuite/gas/riscv/regrel-add.l
 create mode 100644 gas/testsuite/gas/riscv/regrel-add.s
 create mode 100644 gas/testsuite/gas/riscv/regrel-shxadd.d
 create mode 100644 gas/testsuite/gas/riscv/regrel-shxadd.l
 create mode 100644 gas/testsuite/gas/riscv/regrel-shxadd.s

-- 






This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking. 
 
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
  

Comments

Jan Beulich March 24, 2026, 10:07 a.m. UTC | #1
On 24.03.2026 10:44, 翁丽琴 wrote:
> @@ -3089,6 +3107,30 @@ riscv_elf_relocate_section (bfd *output_bfd,
>              break;
>            }
>  
> +    case INTERNAL_R_RISCV_REGREL_LO12_I:
> +    case INTERNAL_R_RISCV_REGREL_LO12_S:
> +      {
> +                bfd_vma gp = riscv_global_pointer_value (info);
> +                if (VALID_ITYPE_IMM (relocation + rel->r_addend - gp))
> +                  {
> +                bfd_vma insn = bfd_getl32 (contents + rel->r_offset);
> +                rel->r_addend -= gp;
> +                bfd_putl32 (insn, contents + rel->r_offset);
> +                  }
> +                else
> +                  r = bfd_reloc_overflow;
> +                break;
> +      }
> +
> +    case INTERNAL_R_RISCV_REGREL_ADD:
> +        case INTERNAL_R_RISCV_REGREL_SHXADD:
> +      {
> +                bfd_vma insn = bfd_getl32 (contents + rel->r_offset);
> +                insn = (insn & ~(OP_MASK_RS2 << OP_SH_RS2)) | (X_GP << OP_SH_RS2);
> +                bfd_putl32 (insn, contents + rel->r_offset);
> +                break;
> +      }

Nit: Entirely bogus indentation.

> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -876,7 +876,70 @@ static const reloc_howto_type howto_table[] =
>           false,                                /* partial_inplace */
>           0,                                /* src_mask */
>           ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
> -         false)                         /* pcrel_offset */
> +          false),                 /* pcrel_offset */

Why the fiddling with existing code?

> +  /* Global array non-constant subscript addressing */
> +  HOWTO (R_RISCV_REGREL_LO12_I,                 /* type */
> +          0,                                 /* rightshift */
> +          4,                                 /* size */
> +          32,                                 /* bitsize */

I realize you copy what other, similar entries have, but are these bit
sizes (and perhaps also sizes) actually sensible? This is a 12-bit
reloc, isn't it?

> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -1957,6 +1957,13 @@ riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value)
>      case BFD_RELOC_RISCV_LO12_I:
>        return ENCODE_ITYPE_IMM (value);
>  
> +

Please don't introduce double blank lines.

> @@ -3631,16 +3644,25 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>                continue;
>  
>              case 'j': /* Sign-extended immediate.  */
> -              p = percent_op_itype;
> -              *imm_reloc = BFD_RELOC_RISCV_LO12_I;
> +                   p = percent_op_itype;
> +                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
> +                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_I;
> +                  else
> +                    *imm_reloc = BFD_RELOC_RISCV_LO12_I;
>                goto alu_op;
>              case 'q': /* Store displacement.  */
> -              p = percent_op_stype;
> -              *imm_reloc = BFD_RELOC_RISCV_LO12_S;
> +                  p = percent_op_stype;
> +                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
> +                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_S;
> +                  else
> +                    *imm_reloc = BFD_RELOC_RISCV_LO12_S;
>                goto load_store;
>              case 'o': /* Load displacement.  */
> -              p = percent_op_itype;
> -              *imm_reloc = BFD_RELOC_RISCV_LO12_I;
> +                  p = percent_op_itype;
> +                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
> +                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_I;
> +                  else
> +                    *imm_reloc = BFD_RELOC_RISCV_LO12_I;
>                goto load_store;

Why all the re-indentation, causing extra churn? And then while causing extra
churn you don't even fix the style problem (using hard tabs for 8 leading
blanks).

> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/regrel-add.d
> @@ -0,0 +1,3 @@
> +#as: -march=rv32ia
> +#source regrel-add.s
> +#error_output: regrel-add.l
> \ No newline at end of file

Please (throughout) can you avoid introduction of files without trailing
newlines?

> --- a/include/elf/riscv.h
> +++ b/include/elf/riscv.h
> @@ -95,6 +95,14 @@ 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)
> +  RELOC_NUMBER (R_RISCV_REGREL_LO12_I, 77)
> +  RELOC_NUMBER (R_RISCV_REGREL_LO12_S, 78)
> +  RELOC_NUMBER (R_RISCV_REGREL_ADD,    79)
> +  RELOC_NUMBER (R_RISCV_REGREL_SHXADD, 80)
> +  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_LO12_I, 81)
> +  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_LO12_S, 82)
> +  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_ADD,    83)
> +  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_SHXADD, 84)

These last four don't appear in the spec (and the numbers used collide with
whatever the spec may assign later). Why do yu need them, when you have ...

>  END_RELOC_NUMBERS (R_RISCV_max)
>  
>  /* Internal relocations used exclusively by the relaxation pass.  */
> @@ -105,6 +113,10 @@ END_RELOC_NUMBERS (R_RISCV_max)
>  #define R_RISCV_GPREL_S           (R_RISCV_max + 4)
>  #define R_RISCV_TPREL_I           (R_RISCV_max + 5)
>  #define R_RISCV_TPREL_S           (R_RISCV_max + 6)
> +#define INTERNAL_R_RISCV_REGREL_LO12_I (R_RISCV_max + 7)
> +#define INTERNAL_R_RISCV_REGREL_LO12_S (R_RISCV_max + 8)
> +#define INTERNAL_R_RISCV_REGREL_ADD    (R_RISCV_max + 9)
> +#define INTERNAL_R_RISCV_REGREL_SHXADD (R_RISCV_max + 10)

... these?

> --- a/opcodes/ChangeLog
> +++ b/opcodes/ChangeLog
> @@ -1,3 +1,7 @@
> +2026-03-24  wengliqin  <liqin.weng@spacemit.com>
> +
> +        * riscv-opc.c: Update relocation definitions for new REGREL types.

I don't think this adequately describes the changes being made. (Such patching
of ChangeLog files shouldn't be done anymore anyway, aiui. If you want ChangeLog
entries, make them part of the commit message.)

Jan
  
Kito Cheng April 14, 2026, 1 a.m. UTC | #2
Hi Li Qin:

You don't need INTERNAL_ variant of relocation, INTERNAL_ relocation
are used only when we need an relocation but it's not defined in
psABI, and it generally will generated during static link time and
discard/resolved at static link time.

And in this case, we will add new relocation type in psABI side, so no
INTERNAL_ relocation is not needed :)
  

Patch

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 6046f658f8b..2abcb80eb0f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@ 
+2026-03-24  wengliqin  <liqin.weng@spacemit.com>
+
+        * reloc.c (BFD_RELOC_RISCV_REGREL12_I, BFD_RELOC_RISCV_REGREL12_S,
+        BFD_RELOC_RISCV_REGREL_LO12_I, BFD_RELOC_RISCV_REGREL_LO12_S,
+        BFD_RELOC_RISCV_REGREL_ADD, BFD_RELOC_RISCV_REGREL_SHXADD): New
+        relocation types.
+        * bfd-in2.h: Regenerate.
+        * libbfd.h: Regenerate.
+        * elfnn-riscv.c (perform_relocation): Add support for new REGREL
+        relocations.
+        (riscv_elf_relocate_section): Handle REGREL relocations for global
+        array accesses with non-constant indices.
+        * elfxx-riscv.c: Define relocation information for new REGREL types.
+
 2025-09-16  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
         * config.bfd <powerpc-*-solaris2*>: Remove.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index bcec515e8be..d465c1bc64e 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5373,8 +5373,8 @@  enum bfd_reloc_code_real
   BFD_RELOC_RISCV_PCREL_LO12_S,
   BFD_RELOC_RISCV_LO12_I,
   BFD_RELOC_RISCV_LO12_S,
-  BFD_RELOC_RISCV_GPREL12_I,
-  BFD_RELOC_RISCV_GPREL12_S,
+  BFD_RELOC_RISCV_REGREL12_I,
+  BFD_RELOC_RISCV_REGREL12_S,
   BFD_RELOC_RISCV_TPREL_HI20,
   BFD_RELOC_RISCV_TPREL_LO12_I,
   BFD_RELOC_RISCV_TPREL_LO12_S,
@@ -5416,6 +5416,10 @@  enum bfd_reloc_code_real
   BFD_RELOC_RISCV_32_PCREL,
   BFD_RELOC_RISCV_SET_ULEB128,
   BFD_RELOC_RISCV_SUB_ULEB128,
+  BFD_RELOC_RISCV_REGREL_LO12_I,
+  BFD_RELOC_RISCV_REGREL_LO12_S,
+  BFD_RELOC_RISCV_REGREL_ADD,
+  BFD_RELOC_RISCV_REGREL_SHXADD,
 
   /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index d3963ec9a58..28b8154b0d1 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1999,7 +1999,9 @@  perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_LO12_I:
+    case R_RISCV_REGREL_LO12_I:
     case R_RISCV_GPREL_I:
+    case INTERNAL_R_RISCV_REGREL_LO12_I:
     case R_RISCV_TPREL_LO12_I:
     case R_RISCV_TPREL_I:
     case R_RISCV_PCREL_LO12_I:
@@ -2009,7 +2011,9 @@  perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_LO12_S:
+    case R_RISCV_REGREL_LO12_S:
     case R_RISCV_GPREL_S:
+    case INTERNAL_R_RISCV_REGREL_LO12_S:
     case R_RISCV_TPREL_LO12_S:
     case R_RISCV_TPREL_S:
     case R_RISCV_PCREL_LO12_S:
@@ -2112,6 +2116,12 @@  perform_relocation (const reloc_howto_type *howto,
         return bfd_reloc_ok;
       }
 
+    case R_RISCV_REGREL_ADD:
+    case R_RISCV_REGREL_SHXADD:
+    case INTERNAL_R_RISCV_REGREL_ADD:
+    case INTERNAL_R_RISCV_REGREL_SHXADD:
+      break;
+
     case R_RISCV_32:
     case R_RISCV_64:
     case R_RISCV_ADD8:
@@ -2722,6 +2732,10 @@  riscv_elf_relocate_section (bfd *output_bfd,
               case R_RISCV_HI20:
               case R_RISCV_LO12_I:
               case R_RISCV_LO12_S:
+              case R_RISCV_REGREL_LO12_I:
+              case R_RISCV_REGREL_LO12_S:
+              case R_RISCV_REGREL_ADD:
+              case R_RISCV_REGREL_SHXADD:
                 goto do_relocation;
 
               case R_RISCV_PCREL_HI20:
@@ -2788,6 +2802,10 @@  riscv_elf_relocate_section (bfd *output_bfd,
         case R_RISCV_RVC_LUI:
         case R_RISCV_LO12_I:
         case R_RISCV_LO12_S:
+        case R_RISCV_REGREL_LO12_I:
+        case R_RISCV_REGREL_LO12_S:
+        case R_RISCV_REGREL_ADD:
+        case R_RISCV_REGREL_SHXADD:
         case R_RISCV_SET6:
         case R_RISCV_SET8:
         case R_RISCV_SET16:
@@ -3089,6 +3107,30 @@  riscv_elf_relocate_section (bfd *output_bfd,
             break;
           }
 
+    case INTERNAL_R_RISCV_REGREL_LO12_I:
+    case INTERNAL_R_RISCV_REGREL_LO12_S:
+      {
+                bfd_vma gp = riscv_global_pointer_value (info);
+                if (VALID_ITYPE_IMM (relocation + rel->r_addend - gp))
+                  {
+                bfd_vma insn = bfd_getl32 (contents + rel->r_offset);
+                rel->r_addend -= gp;
+                bfd_putl32 (insn, contents + rel->r_offset);
+                  }
+                else
+                  r = bfd_reloc_overflow;
+                break;
+      }
+
+    case INTERNAL_R_RISCV_REGREL_ADD:
+        case INTERNAL_R_RISCV_REGREL_SHXADD:
+      {
+                bfd_vma insn = bfd_getl32 (contents + rel->r_offset);
+                insn = (insn & ~(OP_MASK_RS2 << OP_SH_RS2)) | (X_GP << OP_SH_RS2);
+                bfd_putl32 (insn, contents + rel->r_offset);
+                break;
+      }
+
         case R_RISCV_PCREL_HI20:
           absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc, &relocation,
                                                 contents, howto);
@@ -5148,6 +5190,22 @@  _bfd_riscv_relax_lui (bfd *abfd,
           rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
           return true;
 
+        case R_RISCV_REGREL_LO12_I:
+          rel->r_info = ELFNN_R_INFO (sym, INTERNAL_R_RISCV_REGREL_LO12_I);
+          return true;
+
+        case R_RISCV_REGREL_LO12_S:
+          rel->r_info = ELFNN_R_INFO (sym, INTERNAL_R_RISCV_REGREL_LO12_S);
+          return true;
+
+        case R_RISCV_REGREL_ADD:
+          rel->r_info = ELFNN_R_INFO (sym, INTERNAL_R_RISCV_REGREL_ADD);
+          return true;
+
+        case R_RISCV_REGREL_SHXADD:
+          rel->r_info = ELFNN_R_INFO (sym, INTERNAL_R_RISCV_REGREL_SHXADD);
+          return true;
+
         case R_RISCV_HI20:
           /* Delete unnecessary LUI and reuse the reloc.  */
           *again = true;
@@ -5539,7 +5597,11 @@  _bfd_riscv_relax_section (bfd *abfd, asection *sec,
             relax_func = _bfd_riscv_relax_call;
           else if (type == R_RISCV_HI20
                    || type == R_RISCV_LO12_I
-                   || type == R_RISCV_LO12_S)
+                   || type == R_RISCV_LO12_S
+                   || type == R_RISCV_REGREL_LO12_I
+                   || type == R_RISCV_REGREL_LO12_S
+                   || type == R_RISCV_REGREL_ADD
+                   || type == R_RISCV_REGREL_SHXADD)
             relax_func = _bfd_riscv_relax_lui;
           else if (type == R_RISCV_TPREL_HI20
                    || type == R_RISCV_TPREL_ADD
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index ee962b4f6f1..0404eae591e 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -876,7 +876,70 @@  static const reloc_howto_type howto_table[] =
          false,                                /* partial_inplace */
          0,                                /* src_mask */
          ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
-         false)                         /* pcrel_offset */
+          false),                 /* pcrel_offset */
+
+  /* Global array non-constant subscript addressing */
+  HOWTO (R_RISCV_REGREL_LO12_I,                 /* type */
+          0,                                 /* rightshift */
+          4,                                 /* size */
+          32,                                 /* bitsize */
+          false,                         /* pc_relative */
+          0,                                 /* bitpos */
+          complain_overflow_dont,         /* complain_on_overflow */
+          bfd_elf_generic_reloc,                 /* special_function */
+          "R_RISCV_REGREL_LO12_I",         /* name */
+          false,                         /* partial_inplace */
+          0,                                 /* src_mask */
+          ENCODE_ITYPE_IMM (-1U),         /* dst_mask */
+          false),                         /* pcrel_offset */
+
+  HOWTO (R_RISCV_REGREL_LO12_S,                 /* type */
+          0,                                 /* rightshift */
+          4,                                 /* size */
+          32,                                 /* bitsize */
+          false,                         /* pc_relative */
+          0,                                 /* bitpos */
+          complain_overflow_dont,         /* complain_on_overflow */
+          bfd_elf_generic_reloc,                 /* special_function */
+          "R_RISCV_REGREL_LO12_S",         /* name */
+          false,                         /* partial_inplace */
+          0,                                 /* src_mask */
+          ENCODE_STYPE_IMM (-1U),         /* dst_mask */
+          false),                         /* pcrel_offset */
+
+  HOWTO (R_RISCV_REGREL_ADD,                 /* type */
+          0,                                 /* rightshift */
+          4,                                 /* size */
+          32,                                 /* bitsize */
+          false,                         /* pc_relative */
+          0,                                 /* bitpos */
+          complain_overflow_dont,         /* complain_on_overflow */
+          bfd_elf_generic_reloc,                 /* special_function */
+          "R_RISCV_REGREL_ADD",                 /* name */
+          false,                         /* partial_inplace */
+          0,                                 /* src_mask */
+          0,                                 /* dst_mask */
+          false),                         /* pcrel_offset */
+
+  HOWTO (R_RISCV_REGREL_SHXADD,                 /* type */
+          0,                                 /* rightshift */
+          4,                                 /* size */
+          32,                                 /* bitsize */
+          false,                         /* pc_relative */
+          0,                                 /* bitpos */
+          complain_overflow_dont,         /* complain_on_overflow */
+          bfd_elf_generic_reloc,                 /* special_function */
+          "R_RISCV_REGREL_SHXADD",         /* name */
+          false,                         /* partial_inplace */
+          0,                                 /* src_mask */
+          0,                                 /* dst_mask */
+          false),                         /* pcrel_offset */
+
+  EMPTY_HOWTO (70),
+  EMPTY_HOWTO (71),
+  EMPTY_HOWTO (72),
+  EMPTY_HOWTO (73),
+
 };
 
 static const reloc_howto_type howto_table_internal[] =
@@ -961,6 +1024,63 @@  static const reloc_howto_type howto_table_internal[] =
          0,                                /* src_mask */
          ENCODE_STYPE_IMM (-1U),        /* dst_mask */
          false),                        /* pcrel_offset */
+
+  /* Global array non-constant subscript addressing */
+  HOWTO (INTERNAL_R_RISCV_REGREL_LO12_I,                /* type */
+         0,                                /* rightshift */
+         4,                                /* size */
+         32,                                /* bitsize */
+         false,                                /* pc_relative */
+         0,                                /* bitpos */
+         complain_overflow_dont,        /* complain_on_overflow */
+         bfd_elf_generic_reloc,                /* special_function */
+         "INTERNAL_R_RISCV_REGREL_LO12_I",                /* name */
+         false,                                /* partial_inplace */
+         0,                                /* src_mask */
+         ENCODE_ITYPE_IMM (-1U),        /* dst_mask */
+         false),                        /* pcrel_offset */
+
+  HOWTO (INTERNAL_R_RISCV_REGREL_LO12_S,                /* type */
+         0,                                /* rightshift */
+         4,                                /* size */
+         32,                                /* bitsize */
+         false,                                /* pc_relative */
+         0,                                /* bitpos */
+         complain_overflow_dont,        /* complain_on_overflow */
+         bfd_elf_generic_reloc,                /* special_function */
+         "INTERNAL_R_RISCV_REGREL_LO12_S",                /* name */
+         false,                                /* partial_inplace */
+         0,                                /* src_mask */
+         ENCODE_STYPE_IMM (-1U),        /* dst_mask */
+         false),                        /* pcrel_offset */
+
+  HOWTO (INTERNAL_R_RISCV_REGREL_ADD,                /* type */
+         0,                                /* rightshift */
+         4,                                /* size */
+         32,                                /* bitsize */
+         false,                                /* pc_relative */
+         0,                                /* bitpos */
+         complain_overflow_dont,        /* complain_on_overflow */
+         bfd_elf_generic_reloc,                /* special_function */
+         "INTERNAL_R_RISCV_REGREL_ADD",                /* name */
+         false,                                /* partial_inplace */
+         0,                                /* src_mask */
+         0,        /* dst_mask */
+         false),                        /* pcrel_offset */
+
+  HOWTO (INTERNAL_R_RISCV_REGREL_SHXADD,                /* type */
+         0,                                /* rightshift */
+         4,                                /* size */
+         32,                                /* bitsize */
+         false,                                /* pc_relative */
+         0,                                /* bitpos */
+         complain_overflow_dont,        /* complain_on_overflow */
+         bfd_elf_generic_reloc,                /* special_function */
+         "INTERNAL_R_RISCV_REGREL_SHXADD",                /* name */
+         false,                                /* partial_inplace */
+         0,                                /* src_mask */
+         0,        /* dst_mask */
+         false)                        /* pcrel_offset */
 };
 
 /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
@@ -1023,6 +1143,10 @@  static const struct elf_reloc_map riscv_reloc_map[] =
   { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
   { BFD_RELOC_RISCV_SET_ULEB128, R_RISCV_SET_ULEB128 },
   { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
+  { BFD_RELOC_RISCV_REGREL_LO12_I, R_RISCV_REGREL_LO12_I},
+  { BFD_RELOC_RISCV_REGREL_LO12_S, R_RISCV_REGREL_LO12_S},
+  { BFD_RELOC_RISCV_REGREL_ADD, R_RISCV_REGREL_ADD},
+  { BFD_RELOC_RISCV_REGREL_SHXADD, R_RISCV_REGREL_SHXADD},
 };
 
 struct riscv_profiles
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 74c0fe026f0..957127b3305 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2402,6 +2402,10 @@  static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_TLSDESC_LOAD_LO12",
   "BFD_RELOC_RISCV_TLSDESC_ADD_LO12",
   "BFD_RELOC_RISCV_TLSDESC_CALL",
+  "BFD_RELOC_RISCV_REGREL_LO12_I",
+  "BFD_RELOC_RISCV_REGREL_LO12_S",
+  "BFD_RELOC_RISCV_REGREL_ADD",
+  "BFD_RELOC_RISCV_REGREL_SHXADD",
   "BFD_RELOC_RISCV_ALIGN",
   "BFD_RELOC_RISCV_RVC_BRANCH",
   "BFD_RELOC_RISCV_RVC_JUMP",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 98343696a33..f7083747415 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -4861,6 +4861,14 @@  ENUMX
   BFD_RELOC_RISCV_TLSDESC_ADD_LO12
 ENUMX
   BFD_RELOC_RISCV_TLSDESC_CALL
+ENUMX
+  BFD_RELOC_RISCV_REGREL_LO12_I
+ENUMX
+  BFD_RELOC_RISCV_REGREL_LO12_S
+ENUMX
+  BFD_RELOC_RISCV_REGREL_ADD
+ENUMX
+  BFD_RELOC_RISCV_REGREL_SHXADD
 ENUMX
   BFD_RELOC_RISCV_ALIGN
 ENUMX
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 492475658f1..ecceaf1cbee 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,13 @@ 
+2026-03-24  wengliqin  <liqin.weng@spacemit.com>
+
+        * config/tc-riscv.c: Add support for RISC-V REGREL relocations.
+        * testsuite/gas/riscv/regrel-add.s: New test for REGREL_ADD.
+        * testsuite/gas/riscv/regrel-add.d: Corresponding test output.
+        * testsuite/gas/riscv/regrel-add.l: Corresponding test output.
+        * testsuite/gas/riscv/regrel-shxadd.s: New test for REGREL_SHXADD.
+        * testsuite/gas/riscv/regrel-shxadd.d: Corresponding test output.
+        * testsuite/gas/riscv/regrel-shxadd.l: Corresponding test output.
+
 2025-09-16  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
         * NEWS: Mention Solaris/PowerPC removal.
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 17205db68b2..58534e1c037 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1957,6 +1957,13 @@  riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value)
     case BFD_RELOC_RISCV_LO12_I:
       return ENCODE_ITYPE_IMM (value);
 
+
+    case BFD_RELOC_RISCV_REGREL_LO12_S:
+      return ENCODE_STYPE_IMM (value);
+
+    case BFD_RELOC_RISCV_REGREL_LO12_I:
+      return ENCODE_ITYPE_IMM (value);
+
     default:
       abort ();
     }
@@ -2021,7 +2028,9 @@  append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
   if (reloc_type == BFD_RELOC_RISCV_HI20
       || reloc_type == BFD_RELOC_RISCV_PCREL_HI20
       || reloc_type == BFD_RELOC_RISCV_TPREL_HI20
-      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD)
+      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD
+      || reloc_type == BFD_RELOC_RISCV_REGREL_ADD
+      || reloc_type == BFD_RELOC_RISCV_REGREL_SHXADD)
     {
       frag_wane (frag_now);
       frag_new (0);
@@ -2454,6 +2463,7 @@  static const struct percent_op_match percent_op_utype[] =
 static const struct percent_op_match percent_op_itype[] =
 {
   {"lo", BFD_RELOC_RISCV_LO12_I},
+  {"regrel_lo", BFD_RELOC_RISCV_REGREL_LO12_I},
   {"tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_I},
   {"pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_I},
   {"tlsdesc_load_lo", BFD_RELOC_RISCV_TLSDESC_LOAD_LO12},
@@ -2464,6 +2474,7 @@  static const struct percent_op_match percent_op_itype[] =
 static const struct percent_op_match percent_op_stype[] =
 {
   {"lo", BFD_RELOC_RISCV_LO12_S},
+  {"regrel_lo", BFD_RELOC_RISCV_REGREL_LO12_S},
   {"tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_S},
   {"pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_S},
   {0, 0}
@@ -2473,6 +2484,8 @@  static const struct percent_op_match percent_op_relax_only[] =
 {
   {"tlsdesc_call", BFD_RELOC_RISCV_TLSDESC_CALL},
   {"tprel_add", BFD_RELOC_RISCV_TPREL_ADD},
+  {"regrel_add", BFD_RELOC_RISCV_REGREL_ADD},
+  {"regrel_shxadd", BFD_RELOC_RISCV_REGREL_SHXADD},
   {0, 0}
 };
 
@@ -3631,16 +3644,25 @@  riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
               continue;
 
             case 'j': /* Sign-extended immediate.  */
-              p = percent_op_itype;
-              *imm_reloc = BFD_RELOC_RISCV_LO12_I;
+                   p = percent_op_itype;
+                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
+                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_I;
+                  else
+                    *imm_reloc = BFD_RELOC_RISCV_LO12_I;
               goto alu_op;
             case 'q': /* Store displacement.  */
-              p = percent_op_stype;
-              *imm_reloc = BFD_RELOC_RISCV_LO12_S;
+                  p = percent_op_stype;
+                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
+                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_S;
+                  else
+                    *imm_reloc = BFD_RELOC_RISCV_LO12_S;
               goto load_store;
             case 'o': /* Load displacement.  */
-              p = percent_op_itype;
-              *imm_reloc = BFD_RELOC_RISCV_LO12_I;
+                  p = percent_op_itype;
+                  if (strncmp(asarg, "%regrel_lo", 9) == 0)
+                    *imm_reloc = BFD_RELOC_RISCV_REGREL_LO12_I;
+                  else
+                    *imm_reloc = BFD_RELOC_RISCV_LO12_I;
               goto load_store;
             case '1':
               /* This is used for TLS relocations that acts as relaxation
@@ -4686,6 +4708,8 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg)
     case BFD_RELOC_RISCV_HI20:
     case BFD_RELOC_RISCV_LO12_I:
     case BFD_RELOC_RISCV_LO12_S:
+    case BFD_RELOC_RISCV_REGREL_LO12_I:
+    case BFD_RELOC_RISCV_REGREL_LO12_S:
       bfd_putl32 (riscv_apply_const_reloc (fixP->fx_r_type, *valP)
                   | bfd_getl32 (buf), buf);
       if (fixP->fx_addsy == NULL)
@@ -4693,6 +4717,11 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg)
       relaxable = true;
       break;
 
+    case BFD_RELOC_RISCV_REGREL_ADD:
+    case BFD_RELOC_RISCV_REGREL_SHXADD:
+      relaxable = true;
+      break;
+
     case BFD_RELOC_RISCV_GOT_HI20:
       /* R_RISCV_GOT_HI20 and the following R_RISCV_LO12_I are relaxable
          only if it is created as a result of la or lga assembler macros. */
diff --git a/gas/testsuite/gas/riscv/regrel-add.d b/gas/testsuite/gas/riscv/regrel-add.d
new file mode 100644
index 00000000000..27a224d3909
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-add.d
@@ -0,0 +1,3 @@ 
+#as: -march=rv32ia
+#source regrel-add.s
+#error_output: regrel-add.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/riscv/regrel-add.l b/gas/testsuite/gas/riscv/regrel-add.l
new file mode 100644
index 00000000000..e14bff3797e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-add.l
@@ -0,0 +1,3 @@ 
+.*: Assembler messages:
+.*: Error: illegal operands `amoadd.w x8,x9,%regrel_add\(sym\)\(x10\)'
+.*: Error: illegal operands `add a5,a5,a0,0'
\ No newline at end of file
diff --git a/gas/testsuite/gas/riscv/regrel-add.s b/gas/testsuite/gas/riscv/regrel-add.s
new file mode 100644
index 00000000000..613de360534
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-add.s
@@ -0,0 +1,12 @@ 
+    # Don't allow regrel_add in amoadd.
+.option arch, +a
+        amoadd.w x8,x9,%regrel_add(sym)(x10)
+        # Do require regrel_add in 4-operand add.
+        add a5,a5,a0,0
+        .globl        sym
+        .section        .tbss,"awT",@nobits
+        .align        2
+        .type        sym, @object
+        .size        sym, 4
+sym:
+        .zero        4
diff --git a/gas/testsuite/gas/riscv/regrel-shxadd.d b/gas/testsuite/gas/riscv/regrel-shxadd.d
new file mode 100644
index 00000000000..c25aee926ca
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-shxadd.d
@@ -0,0 +1,3 @@ 
+#as: -march=rv64imafdc_zicsr_zifencei_zaamo_zalrsc_zba_zbb_zbc_zbs
+#source regrel-shxadd.s
+#error_output: regrel-shxadd.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/riscv/regrel-shxadd.l b/gas/testsuite/gas/riscv/regrel-shxadd.l
new file mode 100644
index 00000000000..3025e35f399
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-shxadd.l
@@ -0,0 +1,9 @@ 
+.*: Assembler messages:
+.*: Error: illegal operands `amoadd.w x8,x9,%regrel_add\(sym\)\(x10\)'
+.*: Error: illegal operands `sh1add a0,a0,a5,0'
+.*: Error: illegal operands `sh1add.uw a0,a0,a5,0'
+.*: Error: illegal operands `sh2add a0,a0,a5,0'
+.*: Error: illegal operands `sh2add.uw a0,a0,a5,0'
+.*: Error: illegal operands `sh3add a0,a0,a5,0'
+.*: Error: illegal operands `sh3add.uw a0,a0,a5,0'
+.*: Error: illegal operands `add.uw a0,a0,a5,0'
\ No newline at end of file
diff --git a/gas/testsuite/gas/riscv/regrel-shxadd.s b/gas/testsuite/gas/riscv/regrel-shxadd.s
new file mode 100644
index 00000000000..c6836a4584c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/regrel-shxadd.s
@@ -0,0 +1,18 @@ 
+.option arch, +a
+    # Don't allow regrel_add in amoadd.
+        amoadd.w x8,x9,%regrel_add(sym)(x10)
+        # Do require regrel_add in 4-operand add.
+        sh1add            a0,a0,a5,0
+        sh1add.uw        a0,a0,a5,0
+        sh2add           a0,a0,a5,0
+        sh2add.uw        a0,a0,a5,0
+        sh3add            a0,a0,a5,0
+        sh3add.uw        a0,a0,a5,0
+        add.uw      a0,a0,a5,0
+        .globl        sym
+        .section        .tbss,"awT",@nobits
+        .align        2
+        .type        sym, @object
+        .size        sym, 4
+sym:
+        .zero        4
diff --git a/include/ChangeLog b/include/ChangeLog
index 2d05f2e4da1..83d169baf3f 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@ 
+2026-03-24  wengliqin  <liqin.weng@spacemit.com>
+
+        * elf/riscv.h: Define new RISC-V REGREL relocation macros.
+
 2025-07-13  Nick Clifton  <nickc@redhat.com>
 
         * 2.45 Branch point.
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index f6ca3d4acd8..2226a0f55d3 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -95,6 +95,14 @@  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)
+  RELOC_NUMBER (R_RISCV_REGREL_LO12_I, 77)
+  RELOC_NUMBER (R_RISCV_REGREL_LO12_S, 78)
+  RELOC_NUMBER (R_RISCV_REGREL_ADD,    79)
+  RELOC_NUMBER (R_RISCV_REGREL_SHXADD, 80)
+  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_LO12_I, 81)
+  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_LO12_S, 82)
+  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_ADD,    83)
+  RELOC_NUMBER (INTERNAL_R_RISCV_REGREL_SHXADD, 84)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Internal relocations used exclusively by the relaxation pass.  */
@@ -105,6 +113,10 @@  END_RELOC_NUMBERS (R_RISCV_max)
 #define R_RISCV_GPREL_S           (R_RISCV_max + 4)
 #define R_RISCV_TPREL_I           (R_RISCV_max + 5)
 #define R_RISCV_TPREL_S           (R_RISCV_max + 6)
+#define INTERNAL_R_RISCV_REGREL_LO12_I (R_RISCV_max + 7)
+#define INTERNAL_R_RISCV_REGREL_LO12_S (R_RISCV_max + 8)
+#define INTERNAL_R_RISCV_REGREL_ADD    (R_RISCV_max + 9)
+#define INTERNAL_R_RISCV_REGREL_SHXADD (R_RISCV_max + 10)
 
 /* Processor specific flags for the ELF header e_flags field.  */
 
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 56df9a560d1..ab53c7db910 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,7 @@ 
+2026-03-24  wengliqin  <liqin.weng@spacemit.com>
+
+        * riscv-opc.c: Update relocation definitions for new REGREL types.
+
 2025-07-13  Nick Clifton  <nickc@redhat.com>
 
         * 2.45 Branch point.
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 54887c97880..0433d2ca41f 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -1378,16 +1378,23 @@  const struct riscv_opcode riscv_opcodes[] =
 {"rorw",      64, INSN_CLASS_ZBB_OR_ZBKB,  "d,s,<", MATCH_RORIW, MASK_RORIW, match_opcode, INSN_ALIAS },
 
 /* Zba instructions.  */
-{"sh1add",     0, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH1ADD, MASK_SH1ADD, match_opcode, 0 },
-{"sh2add",     0, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH2ADD, MASK_SH2ADD, match_opcode, 0 },
-{"sh3add",     0, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH3ADD, MASK_SH3ADD, match_opcode, 0 },
-{"sh1add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH1ADD_UW, MASK_SH1ADD_UW, match_opcode, 0 },
-{"sh2add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH2ADD_UW, MASK_SH2ADD_UW, match_opcode, 0 },
-{"sh3add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH3ADD_UW, MASK_SH3ADD_UW, match_opcode, 0 },
+{"sh1add",     0, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH1ADD, MASK_SH1ADD, match_opcode, 0 },
+{"sh1add",     0, INSN_CLASS_ZBA,  "d,s,t,1", MATCH_SH1ADD, MASK_SH1ADD, match_opcode, 0 },
+{"sh2add",     0, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH2ADD, MASK_SH2ADD, match_opcode, 0 },
+{"sh2add",     0, INSN_CLASS_ZBA,  "d,s,t,1", MATCH_SH2ADD, MASK_SH2ADD, match_opcode, 0 },
+{"sh3add",     0, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH3ADD, MASK_SH3ADD, match_opcode, 0 },
+{"sh3add",     0, INSN_CLASS_ZBA,  "d,s,t,1", MATCH_SH3ADD, MASK_SH3ADD, match_opcode, 0 },
+{"sh1add.uw", 64, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH1ADD_UW, MASK_SH1ADD_UW, match_opcode, 0 },
+{"sh1add.uw", 64, INSN_CLASS_ZBA,  "d,s,t,1",   MATCH_SH1ADD_UW, MASK_SH1ADD_UW, match_opcode, 0 },
+{"sh2add.uw", 64, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH2ADD_UW, MASK_SH2ADD_UW, match_opcode, 0 },
+{"sh2add.uw", 64, INSN_CLASS_ZBA,  "d,s,t,1",   MATCH_SH2ADD_UW, MASK_SH2ADD_UW, match_opcode, 0 },
+{"sh3add.uw", 64, INSN_CLASS_ZBA,  "d,s,t",   MATCH_SH3ADD_UW, MASK_SH3ADD_UW, match_opcode, 0 },
+{"sh3add.uw", 64, INSN_CLASS_ZBA,  "d,s,t,1",   MATCH_SH3ADD_UW, MASK_SH3ADD_UW, match_opcode, 0 },
 {"zext.w",    64, INSN_CLASS_ZCB_AND_ZBA,  "Cs,Cw", MATCH_C_ZEXT_W, MASK_C_ZEXT_W, match_opcode, INSN_ALIAS },
 {"zext.w",    64, INSN_CLASS_ZBA,  "d,s",   MATCH_ADD_UW, MASK_ADD_UW | MASK_RS2, match_opcode, INSN_ALIAS },
 {"zext.w",    64, INSN_CLASS_I, "d,s",       0, (int) M_ZEXTW, NULL, INSN_MACRO },
 {"add.uw",    64, INSN_CLASS_ZBA,  "d,s,t", MATCH_ADD_UW, MASK_ADD_UW, match_opcode, 0 },
+{"add.uw",    64, INSN_CLASS_ZBA,  "d,s,t,1", MATCH_ADD_UW, MASK_ADD_UW, match_opcode, 0 },
 {"slli.uw",   64, INSN_CLASS_ZBA,  "d,s,>", MATCH_SLLI_UW, MASK_SLLI_UW, match_opcode, 0 },
 
 /* Zbc or zbkc instructions.  */