[PATCH v5] RISC-V: Add new relocation types for global array accesses with non-constant indices

Jiawei jiawei@iscas.ac.cn
Wed Aug 5 13:13:04 GMT 2026


Hi Liqin,

The patch looks good to me overall.

Before committing, please add the declaration of 
'riscv_elf_reloc_type_lookup' to elfxx-riscv.h,
since it is defined in elfxx-riscv.c and used by elfnn-riscv.c.

Please also remove the temporary TODO and fix the remaining GNU comment 
formatting, for example:

/* Make the fourth operand optional.  */

BR,
Jiawei

On  2026/8/4 15:52, Liqin Weng wrote:
> From: wengliqin <liqin.weng@spacemit.com>
>
> This patch introduces support for new RISC-V relocation types
> (R_RISCV_BASE_IDX_*) to enable more efficient code generation for
> global array accesses with non-constant array subscripts.
>
> New Reloc includes :
> R_RISCV_BASE_IDX_LO12_I/R_RISCV_BASE_IDX_LO12_S/R_RISCV_BASE_IDX_ADD
>
> RISC-V PSABI specification: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/489
>
> bfd/ChangeLog:
>
> 	* bfd-in2.h : Add new relocation type.
> 	* elfnn-riscv.c :  Define relocation information for new
>            relocation type.  Convert the internal
>            R_RISCV_BASE_IDX_GPREL_* relocations produced by relaxation
>            back to their public equivalents before they can be written
>            out, e.g. via --emit-relocs/-r.
> 	* elfxx-riscv.c : Add HOWTOs for new relocation type.  Add
>            riscv_internal_reloc_map and riscv_elf_reloc_type_lookup to
>            map each internal-only relaxed relocation type to the
>            elf type that should be emitted in its place.
> 	* libbfd.h: Regenerate.
> 	* reloc.c: Document BFD_RELOC_RISCV_BASE_IDX_* type.
>
> gas/ChangeLog:
>
> 	* config/tc-riscv.c: Add support for RISC-V Base IDX relocations
> 	* testsuite/gas/riscv/base-idx-add.s: New test for BASE_IDX*.
> 	* testsuite/gas/riscv/base-idx-add.d: New test.
> 	* testsuite/gas/riscv/base-idx-add.l: New test.
>
> include/ChangeLog:
>
> 	* elf/riscv.h: Update relocation definitions for new BASE_IDX*
>            Type.
>
> ld/ChangeLog:
>
> 	* testsuite/ld-riscv-elf/base-idx-relax-gp.s: New test source
> 	  exercising base-idx relaxation to gp.
> 	* testsuite/ld-riscv-elf/base-idx-relax-x0.s: New test source
> 	  exercising base-idx relaxation to x0 only, covering both a
> 	  defined symbol (symL) and an undefined weak symbol referenced
> 	  with a non-zero addend (weakL+0x8).
> 	* testsuite/ld-riscv-elf/base-idx-relax-near.ld: New linker
> 	  script placing __global_pointer$ within gp-relaxable range.
> 	* testsuite/ld-riscv-elf/base-idx-relax-far.ld: New linker
> 	  script keeping data out of gp/x0 range so relaxation cannot
> 	  fire.
> 	* testsuite/ld-riscv-elf/base-idx-relax-x0.ld: New linker
> 	  script exercising the x0-only relaxation path.
> 	* testsuite/ld-riscv-elf/base-idx-relax-medlow-near.d,
> 	  testsuite/ld-riscv-elf/base-idx-relax-medlow-near-emit-relocs.d,
> 	  testsuite/ld-riscv-elf/base-idx-relax-medlow-far.d,
> 	  testsuite/ld-riscv-elf/base-idx-relax-medlow-far-emit-relocs.d,
> 	  testsuite/ld-riscv-elf/base-idx-relax-x0.d,
> 	  testsuite/ld-riscv-elf/base-idx-relax-x0-emit-relocs.d: New
> 	  dump tests covering base-idx relaxation to gp and x0 for both
> 	  defined and weak symbols, with and without --emit-relocs;
> 	  confirm the internal R_RISCV_BASE_IDX_GPREL_* relocation types
> 	  never leak into --emit-relocs output.
> 	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Register the new
> 	  base-idx-relax dump tests.
>
> opcodes/ChangeLog:
>
> 	* riscv-opc.c : add new pattern for add/shaxadd/add.uw/shxadd.uw
> 	* riscv-dis.c (print_insn_args): Add a no-op case for the '1'
> 	relaxation-marker operand, so that disassembling an instruction
> 	whose only matching opcode-table row now includes it (e.g. add,
> 	shNadd) no longer hits "undefined modifier" -- the marker
> 	carries no encoding bits, so nothing is printed for it.
> ---
> This Patch update:
> 1. clang-format
> 2. add the weak symbol tests && remove the implement add x0, x0, zero(weak symbol
> may relax gp, so remove 'add a0, a0, zero' will be implemented in the new patch)
> 3. Convert the internal 'R_RISCV_BASE_IDX_GPREL_*' relocations produced
> by relaxation back to their elf equivalents before they can be written
> out, eg. via --emit-relocs/-r.
>
>   bfd/bfd-in2.h                                 |   3 +
>   bfd/elfnn-riscv.c                             |  92 +++++++++++-
>   bfd/elfxx-riscv.c                             | 138 +++++++++++++++++-
>   bfd/libbfd.h                                  |   3 +
>   bfd/reloc.c                                   |   6 +
>   gas/config/tc-riscv.c                         |  34 ++++-
>   gas/testsuite/gas/riscv/base-idx-add.d        |   3 +
>   gas/testsuite/gas/riscv/base-idx-add.l        |  10 ++
>   gas/testsuite/gas/riscv/base-idx-add.s        |  19 +++
>   include/elf/riscv.h                           |   6 +
>   .../ld-riscv-elf/base-idx-relax-far.ld        |  21 +++
>   ld/testsuite/ld-riscv-elf/base-idx-relax-gp.s |  36 +++++
>   .../base-idx-relax-medlow-far-emit-relocs.d   |  65 +++++++++
>   .../ld-riscv-elf/base-idx-relax-medlow-far.d  |  29 ++++
>   .../base-idx-relax-medlow-near-emit-relocs.d  |  63 ++++++++
>   .../ld-riscv-elf/base-idx-relax-medlow-near.d |  27 ++++
>   .../ld-riscv-elf/base-idx-relax-near.ld       |  22 +++
>   .../base-idx-relax-x0-emit-relocs.d           |  63 ++++++++
>   ld/testsuite/ld-riscv-elf/base-idx-relax-x0.d |  27 ++++
>   .../ld-riscv-elf/base-idx-relax-x0.ld         |  28 ++++
>   ld/testsuite/ld-riscv-elf/base-idx-relax-x0.s |  34 +++++
>   ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp    |   6 +
>   opcodes/riscv-dis.c                           |   6 +
>   opcodes/riscv-opc.c                           |  20 +--
>   24 files changed, 743 insertions(+), 18 deletions(-)
>   create mode 100644 gas/testsuite/gas/riscv/base-idx-add.d
>   create mode 100644 gas/testsuite/gas/riscv/base-idx-add.l
>   create mode 100644 gas/testsuite/gas/riscv/base-idx-add.s
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-far.ld
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-gp.s
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far-emit-relocs.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near-emit-relocs.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-near.ld
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-x0-emit-relocs.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-x0.d
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-x0.ld
>   create mode 100644 ld/testsuite/ld-riscv-elf/base-idx-relax-x0.s
>
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index d4e4f8e4375..71044bcd3f1 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -5351,6 +5351,9 @@ enum bfd_reloc_code_real
>     BFD_RELOC_RISCV_TLSDESC_LOAD_LO12,
>     BFD_RELOC_RISCV_TLSDESC_ADD_LO12,
>     BFD_RELOC_RISCV_TLSDESC_CALL,
> +  BFD_RELOC_RISCV_BASE_IDX_LO12_I,
> +  BFD_RELOC_RISCV_BASE_IDX_LO12_S,
> +  BFD_RELOC_RISCV_BASE_IDX_ADD,
>     BFD_RELOC_RISCV_ALIGN,
>     BFD_RELOC_RISCV_RVC_BRANCH,
>     BFD_RELOC_RISCV_RVC_JUMP,
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index d3963ec9a58..f8ed892edf3 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_BASE_IDX_LO12_I:
>       case R_RISCV_GPREL_I:
> +    case R_RISCV_BASE_IDX_GPREL_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_BASE_IDX_LO12_S:
>       case R_RISCV_GPREL_S:
> +    case R_RISCV_BASE_IDX_GPREL_S:
>       case R_RISCV_TPREL_LO12_S:
>       case R_RISCV_TPREL_S:
>       case R_RISCV_PCREL_LO12_S:
> @@ -2130,6 +2134,8 @@ perform_relocation (const reloc_howto_type *howto,
>       case R_RISCV_32_PCREL:
>       case R_RISCV_TLS_DTPREL32:
>       case R_RISCV_TLS_DTPREL64:
> +    case R_RISCV_BASE_IDX_ADD:
> +    case R_RISCV_BASE_IDX_GPREL_ADD:
>         break;
>   
>       case R_RISCV_DELETE:
> @@ -2389,6 +2395,21 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)
>     return true;
>   }
>   
> +static void
> +change_internal_relocs_to_elf_relocs (Elf_Internal_Rela *relocs,
> +				      Elf_Internal_Rela *relend)
> +{
> +  Elf_Internal_Rela *rel;
> +
> +  for (rel = relocs; rel < relend; rel++)
> +    {
> +      unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
> +      unsigned int elf_type = riscv_elf_reloc_type_lookup (r_type);
> +      if (elf_type != r_type)
> +	rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), elf_type);
> +    }
> +}
> +
>   /* Relocate a RISC-V ELF section.
>   
>      The RELOCATE_SECTION function is called by the new ELF backend linker
> @@ -2722,6 +2743,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
>   	      case R_RISCV_HI20:
>   	      case R_RISCV_LO12_I:
>   	      case R_RISCV_LO12_S:
> +	      case R_RISCV_BASE_IDX_LO12_I:
> +	      case R_RISCV_BASE_IDX_LO12_S:
> +	      case R_RISCV_BASE_IDX_ADD:
>   		goto do_relocation;
>   
>   	      case R_RISCV_PCREL_HI20:
> @@ -2788,6 +2812,9 @@ 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_BASE_IDX_LO12_I:
> +	case R_RISCV_BASE_IDX_LO12_S:
> +	case R_RISCV_BASE_IDX_ADD:
>   	case R_RISCV_SET6:
>   	case R_RISCV_SET8:
>   	case R_RISCV_SET16:
> @@ -3089,6 +3116,48 @@ riscv_elf_relocate_section (bfd *output_bfd,
>   	    break;
>   	  }
>   
> +	case R_RISCV_BASE_IDX_GPREL_I:
> +	case R_RISCV_BASE_IDX_GPREL_S:
> +	  {
> +	    /* After relaxation, the ld/st uses (gp + index) as its base
> +	       register, so the immediate encodes the symbol's displacement
> +	       from gp.  perform_relocation will encode the final value
> +	       from (relocation + r_addend).  */
> +	    bfd_vma gp = riscv_global_pointer_value (info);
> +	    bfd_vma disp = relocation + rel->r_addend - gp;
> +	    bool x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend);
> +	    bool gp_base = (r_type == R_RISCV_BASE_IDX_GPREL_I)
> +			     ? VALID_ITYPE_IMM (disp)
> +			     : VALID_STYPE_IMM (disp);
> +	    if (!x0_base)
> +	      {
> +		/* Only when gp is actually used as the base do we need to
> +		   express the immediate as a displacement from gp.  */
> +		if (gp_base)
> +		  rel->r_addend -= gp;
> +		else
> +		  r = bfd_reloc_overflow;
> +	      }
> +	    break;
> +	  }
> +
> +	case R_RISCV_BASE_IDX_GPREL_ADD:
> +	  {
> +	    /* Rewrite rs2 of the add/shXadd instruction to use gp or x0 as the
> +	       base register after relaxation.  The same encoding change
> +	       applies to both add and shXadd — the opcode itself is left
> +	       intact.  */
> +	    bfd_vma insn = bfd_getl32 (contents + rel->r_offset);
> +	    bool x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend);
> +	    insn &= ~(OP_MASK_RS2 << OP_SH_RS2);
> +	    if (!x0_base)
> +	      {
> +		insn |= 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);
> @@ -3434,6 +3503,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
>         goto out;
>       }
>   
> +  change_internal_relocs_to_elf_relocs (relocs, relend);
> +
>     ret = riscv_resolve_pcrel_lo_relocs (&pcrel_relocs);
>    out:
>     riscv_free_pcrel_relocs (&pcrel_relocs);
> @@ -5148,6 +5219,18 @@ _bfd_riscv_relax_lui (bfd *abfd,
>   	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S);
>   	  return true;
>   
> +	case R_RISCV_BASE_IDX_LO12_I:
> +	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_BASE_IDX_GPREL_I);
> +	  return true;
> +
> +	case R_RISCV_BASE_IDX_LO12_S:
> +	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_BASE_IDX_GPREL_S);
> +	  return true;
> +
> +	case R_RISCV_BASE_IDX_ADD:
> +	  rel->r_info = ELFNN_R_INFO (sym, R_RISCV_BASE_IDX_GPREL_ADD);
> +	  return true;
> +
>   	case R_RISCV_HI20:
>   	  /* Delete unnecessary LUI and reuse the reloc.  */
>   	  *again = true;
> @@ -5160,7 +5243,7 @@ _bfd_riscv_relax_lui (bfd *abfd,
>       }
>   
>     /* Can we relax LUI to C.LUI?  Alignment might move the section forward;
> -     account for this assuming page alignment at worst. In the presence of
> +     account for this assuming page alignment at worst. In the presence of
>        RELRO segment the linker aligns it by one page size, therefore sections
>        after the segment can be moved more than one page. */
>   
> @@ -5537,9 +5620,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
>   	  if (type == R_RISCV_CALL
>   	      || type == R_RISCV_CALL_PLT)
>   	    relax_func = _bfd_riscv_relax_call;
> -	  else if (type == R_RISCV_HI20
> -		   || type == R_RISCV_LO12_I
> -		   || type == R_RISCV_LO12_S)
> +	  else if (type == R_RISCV_HI20 || type == R_RISCV_LO12_I
> +		   || type == R_RISCV_LO12_S || type == R_RISCV_BASE_IDX_LO12_I
> +		   || type == R_RISCV_BASE_IDX_LO12_S
> +		   || type == R_RISCV_BASE_IDX_ADD)
>   	    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..0db219b5521 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -876,7 +876,63 @@ 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 */
> +
> +  /* Reserved slots 66-76.  */
> +  EMPTY_HOWTO (66),
> +  EMPTY_HOWTO (67),
> +  EMPTY_HOWTO (68),
> +  EMPTY_HOWTO (69),
> +  EMPTY_HOWTO (70),
> +  EMPTY_HOWTO (71),
> +  EMPTY_HOWTO (72),
> +  EMPTY_HOWTO (73),
> +  EMPTY_HOWTO (74),
> +  EMPTY_HOWTO (75),
> +  EMPTY_HOWTO (76),
> +
> +  /* Global array accesses with non-constant subscript (base + index).  */
> +  HOWTO (R_RISCV_BASE_IDX_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_BASE_IDX_LO12_I", /* name */
> +	 false,			    /* partial_inplace */
> +	 0,			    /* src_mask */
> +	 ENCODE_ITYPE_IMM (-1U),    /* dst_mask */
> +	 false),		    /* pcrel_offset */
> +
> +  HOWTO (R_RISCV_BASE_IDX_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_BASE_IDX_LO12_S", /* name */
> +	 false,			    /* partial_inplace */
> +	 0,			    /* src_mask */
> +	 ENCODE_STYPE_IMM (-1U),    /* dst_mask */
> +	 false),		    /* pcrel_offset */
> +
> +  HOWTO (R_RISCV_BASE_IDX_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_BASE_IDX_ADD", /* name */
> +	 false,			 /* partial_inplace */
> +	 0,			 /* src_mask */
> +	 0,			 /* dst_mask */
> +	 false),		 /* pcrel_offset */
>   };
>   
>   static const reloc_howto_type howto_table_internal[] =
> @@ -961,6 +1017,50 @@ static const reloc_howto_type howto_table_internal[] =
>   	 0,				/* src_mask */
>   	 ENCODE_STYPE_IMM (-1U),	/* dst_mask */
>   	 false),			/* pcrel_offset */
> +
> +  /* Global array accesses with non-constant subscript (base + index),
> +     after relaxation.  */
> +  HOWTO (R_RISCV_BASE_IDX_GPREL_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_BASE_IDX_GPREL_I", /* name */
> +	 false,			     /* partial_inplace */
> +	 0,			     /* src_mask */
> +	 ENCODE_ITYPE_IMM (-1U),     /* dst_mask */
> +	 false),		     /* pcrel_offset */
> +
> +  HOWTO (R_RISCV_BASE_IDX_GPREL_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_BASE_IDX_GPREL_S", /* name */
> +	 false,			     /* partial_inplace */
> +	 0,			     /* src_mask */
> +	 ENCODE_STYPE_IMM (-1U),     /* dst_mask */
> +	 false),		     /* pcrel_offset */
> +
> +  HOWTO (R_RISCV_BASE_IDX_GPREL_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_BASE_IDX_GPREL_ADD", /* name */
> +	 false,			       /* partial_inplace */
> +	 0,			       /* src_mask */
> +	 0,			       /* dst_mask */
> +	 false)
>   };
>   
>   /* A mapping from BFD reloc types to RISC-V ELF reloc types.  */
> @@ -1023,6 +1123,26 @@ 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_BASE_IDX_LO12_I, R_RISCV_BASE_IDX_LO12_I },
> +  { BFD_RELOC_RISCV_BASE_IDX_LO12_S, R_RISCV_BASE_IDX_LO12_S },
> +  { BFD_RELOC_RISCV_BASE_IDX_ADD, R_RISCV_BASE_IDX_ADD },
> +};
> +
> +/* A mapping from internal-only relocation types (produced by the linker's
> +   relaxation passes; numbered after R_RISCV_max and never valid in an
> +   object file) to the elf relocation type that should be substituted
> +   before the type is written out, e.g. for --emit-relocs/-r output.  */
> +struct internal_reloc_map
> +{
> +  unsigned int internal_type;
> +  enum elf_riscv_reloc_type elf_val;
> +};
> +
> +/* TODO: add another internal relocation type  */
> +static const struct internal_reloc_map riscv_internal_reloc_map[] = {
> +    { R_RISCV_BASE_IDX_GPREL_I, R_RISCV_BASE_IDX_LO12_I },
> +    { R_RISCV_BASE_IDX_GPREL_S, R_RISCV_BASE_IDX_LO12_S },
> +    { R_RISCV_BASE_IDX_GPREL_ADD, R_RISCV_BASE_IDX_ADD },
>   };
>   
>   struct riscv_profiles
> @@ -1059,6 +1179,22 @@ riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
>     return NULL;
>   }
>   
> +/* If R_TYPE is one of the internal-only relocation types produced by
> +   relaxation, return the elf relocation type that should be emitted
> +   in its place.  Otherwise return R_TYPE unchanged.  */
> +
> +unsigned int
> +riscv_elf_reloc_type_lookup (unsigned int r_type)
> +{
> +  unsigned int i;
> +
> +  for (i = 0; i < ARRAY_SIZE (riscv_internal_reloc_map); i++)
> +    if (riscv_internal_reloc_map[i].internal_type == r_type)
> +      return riscv_internal_reloc_map[i].elf_val;
> +
> +  return r_type;
> +}
> +
>   reloc_howto_type *
>   riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
>   {
> diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> index a27134dcd78..ef4f96a1747 100644
> --- a/bfd/libbfd.h
> +++ b/bfd/libbfd.h
> @@ -2362,6 +2362,9 @@ 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_BASE_IDX_LO12_I",
> +  "BFD_RELOC_RISCV_BASE_IDX_LO12_S",
> +  "BFD_RELOC_RISCV_BASE_IDX_ADD",
>     "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..6f6ff98c4a5 100644
> --- a/bfd/reloc.c
> +++ b/bfd/reloc.c
> @@ -4861,6 +4861,12 @@ ENUMX
>     BFD_RELOC_RISCV_TLSDESC_ADD_LO12
>   ENUMX
>     BFD_RELOC_RISCV_TLSDESC_CALL
> +ENUMX
> +  BFD_RELOC_RISCV_BASE_IDX_LO12_I
> +ENUMX
> +  BFD_RELOC_RISCV_BASE_IDX_LO12_S
> +ENUMX
> +  BFD_RELOC_RISCV_BASE_IDX_ADD
>   ENUMX
>     BFD_RELOC_RISCV_ALIGN
>   ENUMX
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 6bcf53832a0..11d9db0f977 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -1953,9 +1953,11 @@ riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value)
>         return ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value));
>   
>       case BFD_RELOC_RISCV_LO12_S:
> +    case BFD_RELOC_RISCV_BASE_IDX_LO12_S:
>         return ENCODE_STYPE_IMM (value);
>   
>       case BFD_RELOC_RISCV_LO12_I:
> +    case BFD_RELOC_RISCV_BASE_IDX_LO12_I:
>         return ENCODE_ITYPE_IMM (value);
>   
>       default:
> @@ -2022,7 +2024,8 @@ 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_BASE_IDX_ADD)
>       {
>         frag_wane (frag_now);
>         frag_new (0);
> @@ -2455,6 +2458,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},
> +  {"base_idx_lo", BFD_RELOC_RISCV_BASE_IDX_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},
> @@ -2465,6 +2469,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},
> +  {"base_idx_lo", BFD_RELOC_RISCV_BASE_IDX_LO12_S},
>     {"tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_S},
>     {"pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_S},
>     {0, 0}
> @@ -2474,6 +2479,7 @@ static const struct percent_op_match percent_op_relax_only[] =
>   {
>     {"tlsdesc_call", BFD_RELOC_RISCV_TLSDESC_CALL},
>     {"tprel_add", BFD_RELOC_RISCV_TPREL_ADD},
> +  {"base_idx_add", BFD_RELOC_RISCV_BASE_IDX_ADD},
>     {0, 0}
>   };
>   
> @@ -3644,9 +3650,23 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
>   	      *imm_reloc = BFD_RELOC_RISCV_LO12_I;
>   	      goto load_store;
>   	    case '1':
> -	      /* This is used for TLS relocations that acts as relaxation
> -		 markers and do not change the instruction encoding,
> -		 i.e. %tprel_add and %tlsdesc_call.  */
> +	      /* This operand is a relaxation marker that does not change
> +		 the instruction encoding, e.g. %tprel_add, %tlsdesc_call
> +		 and %base_idx_add.  It is mandatory when a literal ','
> +		 precedes it in the operand string (e.g. "d,s,1" for
> +		 jalr's %tlsdesc_call), in which case that ',' is already
> +		 consumed by the general ',' handling above and *asarg
> +		 points straight at the marker text.  It is optional when
> +		 it directly follows another operand letter with no
> +		 separating ',' in the operand string (e.g. "d,s,t1" on
> +		 add/shNadd/add.uw for %base_idx_add), in which case we
> +		 must recognise here whether it was actually given --
> +		 mirrors the "optional vector mask" handling of 'Vm'
> +		 above.  */
> +	      if (*asarg == '\0')
> +		continue;
> +	      if (*asarg == ',')
> +		++asarg;
>   	      p = percent_op_relax_only;
>   	      goto alu_op;
>   	    case '0': /* AMO displacement, which must be zero.  */
> @@ -4687,6 +4707,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_BASE_IDX_LO12_I:
> +    case BFD_RELOC_RISCV_BASE_IDX_LO12_S:
>         bfd_putl32 (riscv_apply_const_reloc (fixP->fx_r_type, *valP)
>   		  | bfd_getl32 (buf), buf);
>         if (fixP->fx_addsy == NULL)
> @@ -4694,6 +4716,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
>         relaxable = true;
>         break;
>   
> +    case BFD_RELOC_RISCV_BASE_IDX_ADD:
> +      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/base-idx-add.d b/gas/testsuite/gas/riscv/base-idx-add.d
> new file mode 100644
> index 00000000000..488ffbc1956
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/base-idx-add.d
> @@ -0,0 +1,3 @@
> +#as: -march=rv64imafdc_zbb_zba
> +#source: base-idx-add.s
> +#error_output: base-idx-add.l
> diff --git a/gas/testsuite/gas/riscv/base-idx-add.l b/gas/testsuite/gas/riscv/base-idx-add.l
> new file mode 100644
> index 00000000000..8321b40ccc6
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/base-idx-add.l
> @@ -0,0 +1,10 @@
> +.*: Assembler messages:
> +.*: Error: illegal operands `amoadd.w x8,x9,%base_idx_add\(sym\)\(x10\)'
> +.*: Error: illegal operands `add a5,a5,a0,0'
> +.*: 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'
> diff --git a/gas/testsuite/gas/riscv/base-idx-add.s b/gas/testsuite/gas/riscv/base-idx-add.s
> new file mode 100644
> index 00000000000..47d1b3b5aa3
> --- /dev/null
> +++ b/gas/testsuite/gas/riscv/base-idx-add.s
> @@ -0,0 +1,19 @@
> +.option arch, +a
> +    # Don't allow base_idx_add in amoadd.
> +	amoadd.w x8,x9,%base_idx_add(sym)(x10)
> +	# Do require base_idx_add in 4-operand add.
> +	add		a5,a5,a0,0
> +	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/elf/riscv.h b/include/elf/riscv.h
> index f6ca3d4acd8..a19bee4b684 100644
> --- a/include/elf/riscv.h
> +++ b/include/elf/riscv.h
> @@ -95,6 +95,9 @@ 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_BASE_IDX_LO12_I, 77)
> +  RELOC_NUMBER (R_RISCV_BASE_IDX_LO12_S, 78)
> +  RELOC_NUMBER (R_RISCV_BASE_IDX_ADD, 79)
>   END_RELOC_NUMBERS (R_RISCV_max)
>   
>   /* Internal relocations used exclusively by the relaxation pass.  */
> @@ -105,6 +108,9 @@ 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 R_RISCV_BASE_IDX_GPREL_I (R_RISCV_max + 7)
> +#define R_RISCV_BASE_IDX_GPREL_S (R_RISCV_max + 8)
> +#define R_RISCV_BASE_IDX_GPREL_ADD (R_RISCV_max + 9)
>   
>   /* Processor specific flags for the ELF header e_flags field.  */
>   
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-far.ld b/ld/testsuite/ld-riscv-elf/base-idx-relax-far.ld
> new file mode 100644
> index 00000000000..123f9c4cbe9
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-far.ld
> @@ -0,0 +1,21 @@
> +/* Data symbols reachable by lui/auipc+addi but far from __global_pointer$,
> +   so BASE_IDX gp-relaxation cannot fire.  The original instruction sequence
> +   is preserved.  */
> +
> +ENTRY(_start)
> +MEMORY
> +{
> +	rom (rx)  : ORIGIN = 0x10000, LENGTH = 0x1000
> +	ram (!rx) : ORIGIN = 0x100000, LENGTH = 0x1000
> +}
> +SECTIONS {
> +	.text : {
> +		*(.text*)
> +	} >rom
> +
> +	.data : {
> +		*(.data*)
> +	} >ram
> +
> +	__global_pointer$ = 0x20000;
> +}
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-gp.s b/ld/testsuite/ld-riscv-elf/base-idx-relax-gp.s
> new file mode 100644
> index 00000000000..b157b0b79bb
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-gp.s
> @@ -0,0 +1,36 @@
> +	.text
> +	.global _start
> +_start:
> +
> +.ifdef __medlow__
> +	lui	        a1, %hi(symL)
> +	add	        a2, a0, a1, %base_idx_add(symL)
> +	add.uw	        a2, a0, a1, %base_idx_add(symL)
> +	sh1add	        a2, a0, a1, %base_idx_add(symL)
> +	sh2add	        a2, a0, a1, %base_idx_add(symL)
> +	sh3add	        a2, a0, a1, %base_idx_add(symL)
> +	sh3add.uw	a2, a0, a1, %base_idx_add(symL)
> +	lbu     	a3, %base_idx_lo(symL)(a2)
> +	sb      	a3, %base_idx_lo(symL)(a2)
> +
> +	lui	        a1, %hi(weakL)
> +	add	        a2, a0, a1, %base_idx_add(weakL)
> +	add.uw	        a2, a0, a1, %base_idx_add(weakL)
> +	sh1add	        a2, a0, a1, %base_idx_add(weakL)
> +	sh2add	        a2, a0, a1, %base_idx_add(weakL)
> +	sh3add	        a2, a0, a1, %base_idx_add(weakL)
> +	sh3add.uw	a2, a0, a1, %base_idx_add(weakL)
> +	lbu     	a3, %base_idx_lo(weakL)(a2)
> +	sb      	a3, %base_idx_lo(weakL)(a2)
> +.endif
> +
> +	.size	_start, .-_start
> +
> +	.data
> +	.global symL
> +symL:
> +	.dword	0x1111222233334444
> +
> +	.weak	weakL
> +weakL:
> +	.dword	0x5555666677778888
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far-emit-relocs.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far-emit-relocs.d
> new file mode 100644
> index 00000000000..64a2aeb65cc
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far-emit-relocs.d
> @@ -0,0 +1,65 @@
> +#source: base-idx-relax-gp.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-far.ld -melf64lriscv --relax --emit-relocs
> +#objdump: -dr -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+001005b7[ 	]+lui[ 	]+a1,0x100
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_HI20[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00b50633[ 	]+add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+08b5063b[ 	]+add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b52633[ 	]+sh1add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b54633[ 	]+sh2add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b56633[ 	]+sh3add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b5663b[ 	]+sh3add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00064683[ 	]+lbu[ 	]+a3,0\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00d60023[ 	]+sb[ 	]+a3,0\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+001005b7[ 	]+lui[ 	]+a1,0x100
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_HI20[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00b50633[ 	]+add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+08b5063b[ 	]+add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b52633[ 	]+sh1add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b54633[ 	]+sh2add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b56633[ 	]+sh3add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20b5663b[ 	]+sh3add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00864683[ 	]+lbu[ 	]+a3,8\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00d60423[ 	]+sb[ 	]+a3,8\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far.d
> new file mode 100644
> index 00000000000..753518183fe
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-far.d
> @@ -0,0 +1,29 @@
> +#source: base-idx-relax-gp.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-far.ld -melf64lriscv --relax
> +#objdump: -d -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+001005b7[ 	]+lui[ 	]+a1,0x100
> +[ 	]+[0-9a-f]+:[ 	]+00b50633[ 	]+add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+08b5063b[ 	]+add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b52633[ 	]+sh1add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b54633[ 	]+sh2add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b56633[ 	]+sh3add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b5663b[ 	]+sh3add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+00064683[ 	]+lbu[ 	]+a3,0\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+00d60023[ 	]+sb[ 	]+a3,0\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+001005b7[ 	]+lui[ 	]+a1,0x100
> +[ 	]+[0-9a-f]+:[ 	]+00b50633[ 	]+add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+08b5063b[ 	]+add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b52633[ 	]+sh1add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b54633[ 	]+sh2add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b56633[ 	]+sh3add[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+20b5663b[ 	]+sh3add\.uw[ 	]+a2,a0,a1
> +[ 	]+[0-9a-f]+:[ 	]+00864683[ 	]+lbu[ 	]+a3,8\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+00d60423[ 	]+sb[ 	]+a3,8\(a2\)
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near-emit-relocs.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near-emit-relocs.d
> new file mode 100644
> index 00000000000..71caba35bb1
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near-emit-relocs.d
> @@ -0,0 +1,63 @@
> +#source: base-idx-relax-gp.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-near.ld -melf64lriscv --relax --emit-relocs
> +#objdump: -dr -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+00350633[ 	]+add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+0835063b[ 	]+add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20352633[ 	]+sh1add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20354633[ 	]+sh2add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20356633[ 	]+sh3add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+2035663b[ 	]+sh3add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10064683[ 	]+lbu[ 	]+a3,256\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+symL-0x20000
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10d60023[ 	]+sb[ 	]+a3,256\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+symL-0x20000
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00350633[ 	]+add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+0835063b[ 	]+add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20352633[ 	]+sh1add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20354633[ 	]+sh2add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20356633[ 	]+sh3add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+2035663b[ 	]+sh3add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10864683[ 	]+lbu[ 	]+a3,264\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+weakL-0x20000
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10d60423[ 	]+sb[ 	]+a3,264\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+weakL-0x20000
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near.d
> new file mode 100644
> index 00000000000..2249dcde471
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-medlow-near.d
> @@ -0,0 +1,27 @@
> +#source: base-idx-relax-gp.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-near.ld -melf64lriscv --relax
> +#objdump: -d -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+00350633[ 	]+add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+0835063b[ 	]+add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20352633[ 	]+sh1add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20354633[ 	]+sh2add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20356633[ 	]+sh3add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+2035663b[ 	]+sh3add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+10064683[ 	]+lbu[ 	]+a3,256\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+10d60023[ 	]+sb[ 	]+a3,256\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+00350633[ 	]+add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+0835063b[ 	]+add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20352633[ 	]+sh1add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20354633[ 	]+sh2add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+20356633[ 	]+sh3add[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+2035663b[ 	]+sh3add\.uw[ 	]+a2,a0,gp
> +[ 	]+[0-9a-f]+:[ 	]+10864683[ 	]+lbu[ 	]+a3,264\(a2\)
> +[ 	]+[0-9a-f]+:[ 	]+10d60423[ 	]+sb[ 	]+a3,264\(a2\)
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-near.ld b/ld/testsuite/ld-riscv-elf/base-idx-relax-near.ld
> new file mode 100644
> index 00000000000..b04e15d2fb8
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-near.ld
> @@ -0,0 +1,22 @@
> +/* Data symbols sit right next to __global_pointer$ so the gp-relaxable
> +   range is satisfied and R_RISCV_BASE_IDX_* are fully relaxed.  */
> +
> +ENTRY(_start)
> +MEMORY
> +{
> +	rom (rx)  : ORIGIN = 0x10000, LENGTH = 0x1000
> +	ram (!rx) : ORIGIN = 0x20000, LENGTH = 0x1000
> +}
> +SECTIONS {
> +	.text : {
> +		*(.text*)
> +	} >rom
> +
> +	.data : {
> +		__global_pointer$ = .;
> +		/* Pad so that symL sits at gp + 0x100, giving the relaxed
> +		   lbu/sb a non-zero gp-relative immediate.  */
> +		. = . + 0x100;
> +		*(.data*)
> +	} >ram
> +}
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-x0-emit-relocs.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0-emit-relocs.d
> new file mode 100644
> index 00000000000..59ca62578c7
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0-emit-relocs.d
> @@ -0,0 +1,63 @@
> +#source: base-idx-relax-x0.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-x0.ld -melf64lriscv --relax --emit-relocs
> +#objdump: -dr -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+00050533[ 	]+add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+0805053b[ 	]+add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20052533[ 	]+sh1add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20054533[ 	]+sh2add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+20056533[ 	]+sh3add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+2005653b[ 	]+sh3add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10054603[ 	]+lbu[ 	]+a2,256\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+10c50023[ 	]+sb[ 	]+a2,256\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+symL
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*
> +[ 	]+[0-9a-f]+:[ 	]+00050533[ 	]+add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_NONE[ 	]+\*ABS\*\+0x4
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+0805053b[ 	]+add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+20052533[ 	]+sh1add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+20054533[ 	]+sh2add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+20056533[ 	]+sh3add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+2005653b[ 	]+sh3add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_ADD[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+00854603[ 	]+lbu[ 	]+a2,8\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_I[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+00c50423[ 	]+sb[ 	]+a2,8\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_BASE_IDX_LO12_S[ 	]+weakL\+0x8
> +[ 	]+[0-9a-f]+:[ 	]+R_RISCV_RELAX[ 	]+\*ABS\*\+0x8
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.d b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.d
> new file mode 100644
> index 00000000000..c1687ee0699
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.d
> @@ -0,0 +1,27 @@
> +#source: base-idx-relax-x0.s
> +#as: -march=rv64i_zba -mabi=lp64 --defsym __medlow__=1
> +#ld: -Tbase-idx-relax-x0.ld -melf64lriscv --relax
> +#objdump: -d -Mno-aliases
> +
> +.*:[ 	]+file format .*
> +
> +
> +Disassembly of section .text:
> +
> +0+10000 <_start>:
> +[ 	]+[0-9a-f]+:[ 	]+00050533[ 	]+add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+0805053b[ 	]+add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20052533[ 	]+sh1add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20054533[ 	]+sh2add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20056533[ 	]+sh3add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+2005653b[ 	]+sh3add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+10054603[ 	]+lbu[ 	]+a2,256\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+10c50023[ 	]+sb[ 	]+a2,256\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+00050533[ 	]+add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+0805053b[ 	]+add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20052533[ 	]+sh1add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20054533[ 	]+sh2add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+20056533[ 	]+sh3add[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+2005653b[ 	]+sh3add\.uw[ 	]+a0,a0,zero
> +[ 	]+[0-9a-f]+:[ 	]+00854603[ 	]+lbu[ 	]+a2,8\(a0\)
> +[ 	]+[0-9a-f]+:[ 	]+00c50423[ 	]+sb[ 	]+a2,8\(a0\)
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.ld b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.ld
> new file mode 100644
> index 00000000000..883ebeae167
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.ld
> @@ -0,0 +1,28 @@
> +/* Three base-idx-relax cases sharing one gp placement (__global_pointer$ =
> +   0x1000):
> +
> +   - symL is a defined symbol whose address (0x100) fits a 12-bit signed
> +     immediate directly, while its displacement from gp does not, so x0 is
> +     selected both at relaxation time and at final relocation time.
> +
> +   - weakL is an undefined weak symbol referenced with a +0x8 addend, so
> +     both relaxation time (undefined_weak forces x0) and final relocation
> +     time (0 + 0x8 fits a 12-bit immediate) agree on x0.  */
> +
> +ENTRY(_start)
> +MEMORY
> +{
> +	rom (rx)  : ORIGIN = 0x10000, LENGTH = 0x1000
> +	ram (!rx) : ORIGIN = 0x100, LENGTH = 0x1000
> +}
> +SECTIONS {
> +	.text : {
> +		*(.text*)
> +	} >rom
> +
> +	.data : {
> +		*(.data*)
> +	} >ram
> +
> +	__global_pointer$ = 0x1000;
> +}
> diff --git a/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.s b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.s
> new file mode 100644
> index 00000000000..caa2fe7124f
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/base-idx-relax-x0.s
> @@ -0,0 +1,34 @@
> +	.text
> +	.global _start
> +_start:
> +
> +.ifdef __medlow__
> +	lui             a1, %hi(symL)
> +	add	        a0, a0, a1, %base_idx_add(symL)
> +	add.uw	        a0, a0, a1, %base_idx_add(symL)
> +	sh1add	        a0, a0, a1, %base_idx_add(symL)
> +	sh2add	        a0, a0, a1, %base_idx_add(symL)
> +	sh3add	        a0, a0, a1, %base_idx_add(symL)
> +	sh3add.uw	a0, a0, a1, %base_idx_add(symL)
> +	lbu	        a2, %base_idx_lo(symL)(a0)
> +	sb      	a2, %base_idx_lo(symL)(a0)
> +
> +	lui             a1, %hi(weakL+0x8)
> +	add	        a0, a0, a1, %base_idx_add(weakL+0x8)
> +	add.uw	        a0, a0, a1, %base_idx_add(weakL+0x8)
> +	sh1add	        a0, a0, a1, %base_idx_add(weakL+0x8)
> +	sh2add	        a0, a0, a1, %base_idx_add(weakL+0x8)
> +	sh3add	        a0, a0, a1, %base_idx_add(weakL+0x8)
> +	sh3add.uw       a0, a0, a1, %base_idx_add(weakL+0x8)
> +	lbu	        a2, %base_idx_lo(weakL+0x8)(a0)
> +	sb      	a2, %base_idx_lo(weakL+0x8)(a0)
> +.endif
> +
> +	.size	_start, .-_start
> +
> +	.data
> +	.global symL
> +symL:
> +	.dword	0x1111222233334444
> +
> +        .weak	weakL
> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> index 8e26ccff10a..82e906503d4 100644
> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> @@ -154,6 +154,12 @@ if [istarget "riscv*-*-*"] {
>       run_dump_test "code-model-relax-medany-02"
>       run_dump_test "code-model-relax-medany-weakref-01"
>       run_dump_test "code-model-relax-medany-weakref-02"
> +    run_dump_test "base-idx-relax-medlow-near"
> +    run_dump_test "base-idx-relax-medlow-near-emit-relocs"
> +    run_dump_test "base-idx-relax-medlow-far"
> +    run_dump_test "base-idx-relax-medlow-far-emit-relocs"
> +    run_dump_test "base-idx-relax-x0"
> +    run_dump_test "base-idx-relax-x0-emit-relocs"
>       run_dump_test "attr-merge-arch-01"
>       run_dump_test "attr-merge-arch-02"
>       run_dump_test "attr-merge-arch-03"
> diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> index 03c8cf1e344..5a53367fdd6 100644
> --- a/opcodes/riscv-dis.c
> +++ b/opcodes/riscv-dis.c
> @@ -513,6 +513,12 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
>   	    print (info->stream, dis_style_immediate, "0");
>   	  break;
>   
> +	case '1':
> +	  /* This is a relaxation marker operand (e.g. %tprel_add,
> +	     %tlsdesc_call, %base_idx_add) that does not correspond to
> +	     any encoding bits, so there is nothing to print for it.  */
> +	  break;
> +
>   	case 'r':
>   	  print (info->stream, dis_style_register, "%s",
>   		 pd->riscv_gpr_names[EXTRACT_OPERAND (RS3, l)]);
> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> index 54887c97880..86084dbe091 100644
> --- a/opcodes/riscv-opc.c
> +++ b/opcodes/riscv-opc.c
> @@ -556,8 +556,8 @@ const struct riscv_opcode riscv_opcodes[] =
>   {"add",         0, INSN_CLASS_ZCA, "Ct,Cc,CK",  MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS },
>   {"add",         0, INSN_CLASS_ZCA, "Cc,Cc,CL",  MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS },
>   {"add",         0, INSN_CLASS_ZCA, "d,Cz,CV",   MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS },
> -{"add",         0, INSN_CLASS_I, "d,s,t",     MATCH_ADD, MASK_ADD, match_opcode, 0 },
> -{"add",         0, INSN_CLASS_I, "d,s,t,1",   MATCH_ADD, MASK_ADD, match_opcode, 0 },
> +/* make fourth operand (tprel_add/base_idx_add) of add an optional operand.  */
> +{"add",         0, INSN_CLASS_I, "d,s,t1",    MATCH_ADD, MASK_ADD, match_opcode, 0 },
>   {"add",         0, INSN_CLASS_I, "d,s,j",     MATCH_ADDI, MASK_ADDI, match_opcode, INSN_ALIAS },
>   {"la",          0, INSN_CLASS_I, "d,B",       0, (int) M_LA, match_rd_nonzero, INSN_MACRO },
>   {"lla",         0, INSN_CLASS_I, "d,B",       0, (int) M_LLA, NULL, INSN_MACRO },
> @@ -1378,16 +1378,18 @@ 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 },
> +/*  make fourth operand (base_idx_add) of shxadd/shxadd.uw an optional operand.  */
> +{"sh1add",     0, INSN_CLASS_ZBA,  "d,s,t1",  MATCH_SH1ADD, MASK_SH1ADD, match_opcode, 0 },
> +{"sh2add",     0, INSN_CLASS_ZBA,  "d,s,t1",  MATCH_SH2ADD, MASK_SH2ADD, match_opcode, 0 },
> +{"sh3add",     0, INSN_CLASS_ZBA,  "d,s,t1",  MATCH_SH3ADD, MASK_SH3ADD, match_opcode, 0 },
> +{"sh1add.uw", 64, INSN_CLASS_ZBA,  "d,s,t1",  MATCH_SH1ADD_UW, MASK_SH1ADD_UW, match_opcode, 0 },
> +{"sh2add.uw", 64, INSN_CLASS_ZBA,  "d,s,t1",  MATCH_SH2ADD_UW, MASK_SH2ADD_UW, match_opcode, 0 },
> +{"sh3add.uw", 64, INSN_CLASS_ZBA,  "d,s,t1",  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 },
> +/* make fourth operand (base_idx_add) of add.uw an optional operand.  */
> +{"add.uw",    64, INSN_CLASS_ZBA,  "d,s,t1", 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.  */



More information about the Binutils mailing list