Index: gcc/gcc/config/riscv/riscv-protos.h
===================================================================
--- gcc.orig/gcc/config/riscv/riscv-protos.h
+++ gcc/gcc/config/riscv/riscv-protos.h
@@ -28,6 +28,7 @@ enum riscv_symbol_type {
   SYMBOL_ABSOLUTE,
   SYMBOL_PCREL,
   SYMBOL_GOT_DISP,
+  SYMBOL_GPREL,
   SYMBOL_TLS,
   SYMBOL_TLS_LE,
   SYMBOL_TLS_IE,
Index: gcc/gcc/config/riscv/riscv.c
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.c
+++ gcc/gcc/config/riscv/riscv.c
@@ -559,7 +559,13 @@ riscv_classify_symbol (const_rtx x)
   if (GET_CODE (x) == SYMBOL_REF && flag_pic && !riscv_symbol_binds_local_p (x))
     return SYMBOL_GOT_DISP;
 
-  return riscv_cmodel == CM_MEDLOW ? SYMBOL_ABSOLUTE : SYMBOL_PCREL;
+  if (riscv_cmodel == CM_MEDLOW)
+    return SYMBOL_ABSOLUTE;
+
+  if (LABEL_REF_P (x) || (SYMBOL_REF_P (x) && SYMBOL_REF_FUNCTION_P (x)))
+    return SYMBOL_PCREL;
+
+  return TARGET_GPREL ? SYMBOL_GPREL : SYMBOL_PCREL;
 }
 
 /* Classify the base of symbolic expression X.  */
@@ -604,6 +610,7 @@ riscv_symbolic_constant_p (rtx x, enum r
     case SYMBOL_ABSOLUTE:
     case SYMBOL_PCREL:
     case SYMBOL_TLS_LE:
+    case SYMBOL_GPREL:
       /* GAS rejects offsets outside the range [-2^31, 2^31-1].  */
       return sext_hwi (INTVAL (offset), 32) == INTVAL (offset);
 
@@ -622,6 +629,7 @@ static int riscv_symbol_insns (enum risc
     case SYMBOL_ABSOLUTE: return 2; /* LUI + the reference.  */
     case SYMBOL_PCREL: return 2; /* AUIPC + the reference.  */
     case SYMBOL_TLS_LE: return 3; /* LUI + ADD TP + the reference.  */
+    case SYMBOL_GPREL: return 3; /* LUI + ADD GP + the reference.  */
     case SYMBOL_GOT_DISP: return 3; /* AUIPC + LD GOT + the reference.  */
     default: gcc_unreachable ();
     }
@@ -735,7 +743,9 @@ riscv_split_symbol_type (enum riscv_symb
   if (!TARGET_EXPLICIT_RELOCS)
     return false;
 
-  return symbol_type == SYMBOL_ABSOLUTE || symbol_type == SYMBOL_PCREL;
+  return (symbol_type == SYMBOL_ABSOLUTE
+	  || symbol_type == SYMBOL_PCREL
+	  || symbol_type == SYMBOL_GPREL);
 }
 
 /* Return true if a LO_SUM can address a value of mode MODE when the
@@ -1241,6 +1251,17 @@ riscv_split_symbol (rtx temp, rtx addr,
 	}
 	break;
 
+      case SYMBOL_GPREL:
+	{
+	  rtx high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
+	  rtx gp = gen_rtx_REG (Pmode, GP_REGNUM);
+	  high = riscv_force_temporary (temp, high, in_splitter);
+	  rtx reg = gen_rtx_PLUS (Pmode, high, gp);
+	  reg = riscv_force_temporary (temp, reg, in_splitter);
+	  *low_out = gen_rtx_LO_SUM (Pmode, reg, addr);
+	}
+	break;
+
       default:
 	gcc_unreachable ();
       }
@@ -2030,6 +2051,7 @@ riscv_output_move (rtx dest, rtx src)
 	  case SYMBOL_GOT_DISP: return "la\t%0,%1";
 	  case SYMBOL_ABSOLUTE: return "lla\t%0,%1";
 	  case SYMBOL_PCREL: return "lla\t%0,%1";
+	  case SYMBOL_GPREL: return "la\t%0,%1";
 	  default: gcc_unreachable ();
 	  }
     }
@@ -3290,6 +3312,10 @@ riscv_print_operand_reloc (FILE *file, r
 	reloc = hi_reloc ? "%tprel_hi" : "%tprel_lo";
 	break;
 
+      case SYMBOL_GPREL:
+	reloc = hi_reloc ? "%gprel_hi" : "%gprel_lo";
+	break;
+
       default:
 	output_operand_lossage ("invalid use of '%%%c'", hi_reloc ? 'h' : 'R');
 	return;
@@ -4735,7 +4761,7 @@ riscv_option_override (void)
   /* We get better code with explicit relocs for CM_MEDLOW, but
      worse code for the others (for now).  Pick the best default.  */
   if ((target_flags_explicit & MASK_EXPLICIT_RELOCS) == 0)
-    if (riscv_cmodel == CM_MEDLOW)
+    if (riscv_cmodel == CM_MEDLOW || TARGET_GPREL)
       target_flags |= MASK_EXPLICIT_RELOCS;
 
   /* Require that the ISA supports the requested floating-point ABI.  */
Index: gcc/gcc/config/riscv/riscv.md
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.md
+++ gcc/gcc/config/riscv/riscv.md
@@ -28,6 +28,7 @@
   UNSPEC_ADDRESS_FIRST
   UNSPEC_PCREL
   UNSPEC_LOAD_GOT
+  UNSPEC_GPREL
   UNSPEC_TLS
   UNSPEC_TLS_LE
   UNSPEC_TLS_IE
Index: gcc/gcc/config/riscv/riscv.opt
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.opt
+++ gcc/gcc/config/riscv/riscv.opt
@@ -179,3 +179,7 @@ Use the given offset for addressing the
 
 TargetVariable
 long riscv_stack_protector_guard_offset = 0
+
+mgprel
+Target Report Mask(GPREL)
+Use GP-relative sequences for data accesses.
