diff --git a/bfd/cpu-riscv.c b/bfd/cpu-riscv.c
index a478797da69..d46c36b3110 100644
--- a/bfd/cpu-riscv.c
+++ b/bfd/cpu-riscv.c
@@ -142,6 +142,16 @@ riscv_get_priv_spec_class_from_numbers (unsigned int major,
   *class = class_t;
 }
 
+/* Check if the value of Tag_RISCV_x3_reg_usage is defined or not.  */
+
+bool
+riscv_elf_is_unknown_x3_reg_usage (int value)
+{
+  return (value != X3_DEFAULT
+	  && value != X3_RELAX
+	  && value != X3_RESERVED);
+}
+
 /* Define mapping symbols for riscv.  */
 
 bool
diff --git a/bfd/cpu-riscv.h b/bfd/cpu-riscv.h
index 812596db1c6..7512596e794 100644
--- a/bfd/cpu-riscv.h
+++ b/bfd/cpu-riscv.h
@@ -81,5 +81,15 @@ riscv_get_priv_spec_class_from_numbers (unsigned int,
 					unsigned int,
 					enum riscv_spec_class *);
 
+enum riscv_x3_reg_usage
+{
+  X3_DEFAULT = 0,
+  X3_RELAX,
+  X3_RESERVED = 4,
+};
+
+extern bool
+riscv_elf_is_unknown_x3_reg_usage (int);
+
 extern bool
 riscv_elf_is_mapping_symbols (const char *);
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 09aa7be225e..cc8028ee712 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -235,6 +235,9 @@ struct riscv_elf_link_hash_table
 
   /* Relocations for variant CC symbols may be present.  */
   int variant_cc;
+
+  /* The usage of x3, will be updated to output elf attribute.  */
+  int x3_reg_usage;
 };
 
 /* Instruction access functions. */
@@ -3852,6 +3855,15 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
 	 initialized.  */
       out_attr[0].i = 1;
 
+      /* Filter the unknow value for Tag_RISCV_x3_reg_usage.  */
+      if (riscv_elf_is_unknown_x3_reg_usage (out_attr[Tag_RISCV_x3_reg_usage].i))
+	out_attr[Tag_RISCV_x3_reg_usage].i = X3_DEFAULT;
+      /* Disable gp relaxations if x3 is reserved.
+	 The priority of elf x3_reg_usage attribute is higher than the ld
+	 --[no-]relax-gp options.  */
+      if (out_attr[Tag_RISCV_x3_reg_usage].i == X3_RESERVED)
+	riscv_elf_hash_table (info)->params->relax_gp = false;
+
       return true;
     }
 
@@ -3968,6 +3980,30 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
 	  }
 	break;
 
+      case Tag_RISCV_x3_reg_usage:
+	/* Filter the unknow value for Tag_RISCV_x3_reg_usage.  */
+	if (riscv_elf_is_unknown_x3_reg_usage (in_attr[Tag_RISCV_x3_reg_usage].i))
+	  in_attr[Tag_RISCV_x3_reg_usage].i = X3_DEFAULT;
+
+	if (out_attr[i].i == X3_DEFAULT)
+	  out_attr[i].i = in_attr[i].i;
+	else if (in_attr[i].i != X3_DEFAULT
+		 && out_attr[i].i != in_attr[i].i)
+	  {
+	    _bfd_error_handler
+	      (_("error: %pB use Tag_RISCV_x3_reg_usage (%d) but output "
+		 "use Tag_RISCV_x3_reg_usage (%d)"),
+	       ibfd, in_attr[i].i, out_attr[i].i);
+	    result = false;
+	  }
+
+	/* Disable gp relaxations if x3 is reserved.
+	   The priority of elf x3_reg_usage attribute is higher than the ld
+	   --[no-]relax-gp options.  */
+	if (out_attr[i].i == X3_RESERVED)
+	  riscv_elf_hash_table (info)->params->relax_gp = false;
+	break;
+
       default:
 	result &= _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i);
       }
@@ -4635,6 +4671,9 @@ _bfd_riscv_relax_lui (bfd *abfd,
       || (symval < gp
 	  && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
     {
+      if (!undefined_weak && gp)
+	htab->x3_reg_usage = X3_RELAX;
+
       unsigned sym = ELFNN_R_SYM (rel->r_info);
       switch (ELFNN_R_TYPE (rel->r_info))
 	{
@@ -4899,6 +4938,9 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
       || (symval < gp
 	  && VALID_ITYPE_IMM (symval - gp - max_alignment - reserve_size)))
     {
+      if (!undefined_weak && gp)
+	htab->x3_reg_usage = X3_RELAX;
+
       unsigned sym = hi_reloc.hi_sym;
       switch (ELFNN_R_TYPE (rel->r_info))
 	{
@@ -4945,6 +4987,18 @@ bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info,
   htab->data_segment_phase = data_segment_phase;
 }
 
+/* Called by after_allocation, after all the relaxations (ldelf_map_segments)
+   finishing, to update the value of output Tag_RISCV_x3_reg_usage.  */
+
+void
+bfd_elfNN_riscv_update_x3_reg_usage (struct bfd_link_info *info)
+{
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  enum riscv_x3_reg_usage x = htab->x3_reg_usage == X3_RELAX
+			      ? X3_RELAX : X3_RESERVED;
+  bfd_elf_add_proc_attr_int (info->output_bfd, Tag_RISCV_x3_reg_usage, x);
+}
+
 /* Relax a section.
 
    Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs and
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index abcb409bd78..584337048c2 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -123,3 +123,8 @@ extern void
 bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
 extern void
 bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
+
+extern void
+bfd_elf32_riscv_update_x3_reg_usage (struct bfd_link_info *);
+extern void
+bfd_elf64_riscv_update_x3_reg_usage (struct bfd_link_info *);
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5c69efcbcd7..264ef7efa9e 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -18475,6 +18475,7 @@ static struct riscv_attr_tag_t riscv_attr_tag[] =
   T(priv_spec_revision),
   T(unaligned_access),
   T(stack_align),
+  T(x3_reg_usage),
 #undef T
 };
 
@@ -18531,6 +18532,21 @@ display_riscv_attribute (unsigned char *p,
     case Tag_RISCV_arch:
       p = display_tag_value (-1, p, end);
       break;
+    case Tag_RISCV_x3_reg_usage:
+      READ_ULEB (val, p, end);
+      switch (val)
+	{
+	case 1:
+	  printf (_("relaxation\n"));
+	  break;
+	case 4:
+	  printf (_("reserved\n"));
+	  break;
+	default:
+	  printf (_("unknown\n"));
+	  break;
+	}
+      break;
     default:
       return display_tag_value (tag, p, end);
     }
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index cf6e0d8b015..dcd0d59bd0e 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -5036,6 +5036,7 @@ riscv_convert_symbolic_attribute (const char *name)
     T(priv_spec_revision),
     T(unaligned_access),
     T(stack_align),
+    T(x3_reg_usage),
 #undef T
   };
 
@@ -5090,6 +5091,17 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
 		   "any instructions"));
       break;
 
+    /* The usage of x3,
+       0: default.
+       1: gp relaxation.
+       4: reserved.
+       others: not defined yet.  */
+    case Tag_RISCV_x3_reg_usage:
+      attr = elf_known_obj_attributes_proc (stdoutput);
+      if (riscv_elf_is_unknown_x3_reg_usage (attr[tag].i))
+	as_warn (_("unknown value for Tag_RISCV_x3_reg_usage"));
+      break;
+
     default:
       break;
     }
diff --git a/gas/testsuite/gas/riscv/attribute-x3-reg-usage-relax.d b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-relax.d
new file mode 100644
index 00000000000..a41fa0835ae
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-relax.d
@@ -0,0 +1,6 @@
+#as: -defsym __relax__=1
+#readelf: -A
+#source: attribute-x3-reg-usage.s
+
+#...
+  Tag_RISCV_x3_reg_usage: relaxation
diff --git a/gas/testsuite/gas/riscv/attribute-x3-reg-usage-reserved.d b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-reserved.d
new file mode 100644
index 00000000000..5b82da49f77
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-reserved.d
@@ -0,0 +1,6 @@
+#as: -defsym __reserved__=1
+#readelf: -A
+#source: attribute-x3-reg-usage.s
+
+#...
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.d b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.d
new file mode 100644
index 00000000000..750d6a47d4f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.d
@@ -0,0 +1,7 @@
+#as: -defsym __unknown__=1
+#readelf: -A
+#source: attribute-x3-reg-usage.s
+#warning_output: attribute-x3-reg-usage-unknown.l
+
+#...
+  Tag_RISCV_x3_reg_usage: unknown
diff --git a/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.l b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.l
new file mode 100644
index 00000000000..af9d48ea53a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-x3-reg-usage-unknown.l
@@ -0,0 +1,4 @@
+.*Assembler messages:
+.*Warning: unknown value for Tag_RISCV_x3_reg_usage
+.*Warning: unknown value for Tag_RISCV_x3_reg_usage
+.*Warning: unknown value for Tag_RISCV_x3_reg_usage
diff --git a/gas/testsuite/gas/riscv/attribute-x3-reg-usage.s b/gas/testsuite/gas/riscv/attribute-x3-reg-usage.s
new file mode 100644
index 00000000000..d7452c8ae63
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-x3-reg-usage.s
@@ -0,0 +1,13 @@
+.ifdef __relax__
+.attribute Tag_RISCV_x3_reg_usage, 1
+.endif
+
+.ifdef __reserved__
+.attribute Tag_RISCV_x3_reg_usage, 4
+.endif
+
+.ifdef __unknown__
+.attribute Tag_RISCV_x3_reg_usage, 2
+.attribute Tag_RISCV_x3_reg_usage, 3
+.attribute Tag_RISCV_x3_reg_usage, 5
+.endif
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 0aa8b3359c4..0a7c176d37d 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -144,7 +144,8 @@ enum
   Tag_RISCV_unaligned_access = 6,
   Tag_RISCV_priv_spec = 8,
   Tag_RISCV_priv_spec_minor = 10,
-  Tag_RISCV_priv_spec_revision = 12
+  Tag_RISCV_priv_spec_revision = 12,
+  Tag_RISCV_x3_reg_usage = 16,
 };
 
 #endif /* _ELF_RISCV_H */
diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em
index bb6298d3e8d..b29829fa9df 100644
--- a/ld/emultempl/riscvelf.em
+++ b/ld/emultempl/riscvelf.em
@@ -111,6 +111,8 @@ gld${EMULATION_NAME}_after_allocation (void)
   bfd_elf${ELFSIZE}_riscv_set_data_segment_info (&link_info, (int *) phase);
 
   ldelf_map_segments (need_layout);
+
+  bfd_elf${ELFSIZE}_riscv_update_x3_reg_usage (&link_info);
 }
 
 /* This is a convenient point to tell BFD about target specific flags.
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-01.d b/ld/testsuite/ld-riscv-elf/attr-merge-arch-01.d
index de87f600387..5cd8a193e61 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-arch-01.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-01.d
@@ -7,3 +7,4 @@
 Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: "rv32i2p1_a2p0"
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-02.d b/ld/testsuite/ld-riscv-elf/attr-merge-arch-02.d
index 381ef850d97..7c65f07efd9 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-arch-02.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-02.d
@@ -7,3 +7,4 @@
 Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: "rv32i2p1_a2p0"
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-03.d b/ld/testsuite/ld-riscv-elf/attr-merge-arch-03.d
index 6419fe89791..f6b2ab4a057 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-arch-03.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-03.d
@@ -7,3 +7,4 @@
 Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: "rv32i2p1_a2p0_xbar2p0_xfoo2p0"
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-01.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-01.d
index 0aa6fe0701b..fef683fb8b6 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-01.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-01.d
@@ -10,3 +10,4 @@ File Attributes
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 9
   Tag_RISCV_priv_spec_revision: 1
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-02.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-02.d
index 0ac4ca7c045..56f90e3eb24 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-02.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-02.d
@@ -10,3 +10,4 @@ File Attributes
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 9
   Tag_RISCV_priv_spec_revision: 1
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-03.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-03.d
index 69504839d72..e983615113f 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-03.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-03.d
@@ -10,3 +10,4 @@ File Attributes
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 9
   Tag_RISCV_priv_spec_revision: 1
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-01.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-01.d
index 3509caeed58..ce88e8b8f72 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-01.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-01.d
@@ -11,3 +11,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-02.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-02.d
index 88defe1dced..ffdb9d06d38 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-02.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-02.d
@@ -11,3 +11,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-03.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-03.d
index 7a1b977bbcf..1fa45cf0b76 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-03.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-03.d
@@ -12,3 +12,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-04.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-04.d
index 37b8afcff6f..59352fbb2b7 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-04.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-04.d
@@ -12,3 +12,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-05.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-05.d
index 30446c9dd3e..0a77c90d607 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-05.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-05.d
@@ -12,3 +12,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-06.d b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-06.d
index 8c7624c8daa..92ead2e5f46 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-06.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-06.d
@@ -12,3 +12,4 @@ File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_priv_spec: 1
   Tag_RISCV_priv_spec_minor: 11
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-01.d b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-01.d
index 10399307bbb..eaa102f62db 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-01.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-01.d
@@ -8,3 +8,4 @@ Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_unaligned_access: Unaligned access
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-02.d b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-02.d
index 12ca1c4dd31..3c84581570a 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-02.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-02.d
@@ -8,3 +8,4 @@ Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_unaligned_access: Unaligned access
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-03.d b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-03.d
index e41351da011..71d26b2d6fd 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-03.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-03.d
@@ -8,3 +8,4 @@ Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_unaligned_access: Unaligned access
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-04.d b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-04.d
index ac2a766cfca..83c37c69cba 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-04.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-04.d
@@ -7,3 +7,4 @@
 Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-05.d b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-05.d
index 608c05e8c38..ea6d4ddeede 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-05.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-strict-align-05.d
@@ -8,3 +8,4 @@ Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: [a-zA-Z0-9_\"].*
   Tag_RISCV_unaligned_access: Unaligned access
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-user-ext-01.d b/ld/testsuite/ld-riscv-elf/attr-merge-user-ext-01.d
index f4012dcf90d..33ecc5ec6e4 100644
--- a/ld/testsuite/ld-riscv-elf/attr-merge-user-ext-01.d
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-user-ext-01.d
@@ -7,3 +7,4 @@
 Attribute Section: riscv
 File Attributes
   Tag_RISCV_arch: "rv32i2p1_a2p1"
+  Tag_RISCV_x3_reg_usage: reserved
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-attrs.s b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-attrs.s
new file mode 100644
index 00000000000..b14959faed9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-attrs.s
@@ -0,0 +1,11 @@
+.ifdef __relax__
+.attribute Tag_RISCV_x3_reg_usage, 1
+.endif
+
+.ifdef __reserved__
+.attribute Tag_RISCV_x3_reg_usage, 4
+.endif
+
+.ifdef __unknown__
+.attribute Tag_RISCV_x3_reg_usage, 5
+.endif
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-code.s b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-code.s
new file mode 100644
index 00000000000..895edfdc51b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-code.s
@@ -0,0 +1,12 @@
+	.text
+	.globl _start
+_start:
+	lla	a0, x
+	lui	a1, %hi(x)
+	addi	a1, a1, %lo(x)
+
+	.data
+	.word 0x0
+	.globl x
+x:
+        .word 0x1
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-default.d b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-default.d
new file mode 100644
index 00000000000..1756ac34b9f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-default.d
@@ -0,0 +1,14 @@
+#source: attr-merge-x3-reg-usage-code.s
+#source: attr-merge-x3-reg-usage-attrs.s
+#as:
+#ld:
+#objdump: -d -Mno-aliases
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section \.text:
+
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a0,gp,\-[0-9]+ # [0-9a-f]+ <x>
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a1,gp,\-[0-9]+ # [0-9a-f]+ <x>
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-01.s b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-01.s
new file mode 100644
index 00000000000..f0581182aaa
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-01.s
@@ -0,0 +1 @@
+.attribute Tag_RISCV_x3_reg_usage, 1
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-02.s b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-02.s
new file mode 100644
index 00000000000..0820a45fadb
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail-02.s
@@ -0,0 +1 @@
+.attribute Tag_RISCV_x3_reg_usage, 4
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail.d b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail.d
new file mode 100644
index 00000000000..52955054f1e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-fail.d
@@ -0,0 +1,5 @@
+#source: attr-merge-x3-reg-usage-fail-01.s
+#source: attr-merge-x3-reg-usage-fail-02.s
+#as:
+#ld:
+#error: .*use Tag_RISCV_x3_reg_usage \(4\) but output use Tag_RISCV_x3_reg_usage \(1\)
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-relax.d b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-relax.d
new file mode 100644
index 00000000000..08e1afcae70
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-relax.d
@@ -0,0 +1,14 @@
+#source: attr-merge-x3-reg-usage-code.s
+#source: attr-merge-x3-reg-usage-attrs.s
+#as: --defsym __relax__=1
+#ld:
+#objdump: -d -Mno-aliases
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section \.text:
+
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a0,gp,\-[0-9]+ # [0-9a-f]+ <x>
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a1,gp,\-[0-9]+ # [0-9a-f]+ <x>
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-reserved.d b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-reserved.d
new file mode 100644
index 00000000000..548c986534a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-reserved.d
@@ -0,0 +1,16 @@
+#source: attr-merge-x3-reg-usage-code.s
+#source: attr-merge-x3-reg-usage-attrs.s
+#as: --defsym __reserved__=1
+#ld:
+#objdump: -d -Mno-aliases
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section \.text:
+
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+auipc[ 	]+a0,0x[0-9a-f]+
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a0,a0,[0-9]+ # [0-9a-f]+ <x>
+.*:[ 	]+[0-9a-f]+[ 	]+lui[ 		]+a1,0x[0-9a-f]+
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a1,a1,[0-9]+ # [0-9a-f]+ <x>
diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-unknown.d b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-unknown.d
new file mode 100644
index 00000000000..4e02b32d759
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/attr-merge-x3-reg-usage-unknown.d
@@ -0,0 +1,15 @@
+#source: attr-merge-x3-reg-usage-code.s
+#source: attr-merge-x3-reg-usage-attrs.s
+#as: --defsym __unknown__=1
+#ld:
+#objdump: -d -Mno-aliases
+#warning: .*unknown value for Tag_RISCV_x3_reg_usage.*
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section \.text:
+
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a0,gp,\-[0-9]+ # [0-9a-f]+ <x>
+.*:[ 	]+[0-9a-f]+[ 	]+addi[ 	]+a1,gp,\-[0-9]+ # [0-9a-f]+ <x>
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 947a266ba72..51866313591 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -170,6 +170,11 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "attr-merge-priv-spec-failed-04"
     run_dump_test "attr-merge-priv-spec-failed-05"
     run_dump_test "attr-merge-priv-spec-failed-06"
+    run_dump_test "attr-merge-x3-reg-usage-default"
+    run_dump_test "attr-merge-x3-reg-usage-relax"
+    run_dump_test "attr-merge-x3-reg-usage-reserved"
+    run_dump_test "attr-merge-x3-reg-usage-unknown"
+    run_dump_test "attr-merge-x3-reg-usage-fail"
     run_dump_test "attr-phdr"
     run_dump_test "relax-max-align-gp"
     run_dump_test "uleb128"
