diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 00f034a6751..0dd9b27c8ae 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -862,6 +862,47 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		 ifunc symbol.  */
 	      h->plt.refcount += 1;
 	    }
+
+	  /* The non-preemptible absolute symbol shouldn't be referneced with
+	     pc-relative relocation when generating shared object.  However,
+	     PCREL_HI20/LO12 relocs are always bind locally when generating
+	     shared object, so all absolute symbol referenced need to be
+	     disallowed, except they are defined in linker script.
+
+	     Maybe we should add this check for all pc-relative relocations,
+	     please see pr28789 and pr25749 for details.  */
+	  if (bfd_link_pic (info)
+	      /* (h == NULL || SYMBOL_REFERENCES_LOCAL (info, h))  */
+	      && is_abs_symbol)
+	    {
+	      if (h != NULL && (h)->root.ldscript_def)
+		/* Disallow the absolute symbol defined in linker script here
+		   will cause the glibc-linux toolchain build failed, so regard
+		   them as pc-relative symbols, just like what x86 did.  */
+		;
+	      else
+		{
+		  const char *name;
+		  if (h->root.root.string)
+		    name = h->root.root.string;
+		  else
+		    {
+		      Elf_Internal_Sym *sym;
+		      sym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd,
+						   r_symndx);
+		      name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
+		    }
+
+		  reloc_howto_type *r_t =
+			riscv_elf_rtype_to_howto (abfd, r_type);
+		  _bfd_error_handler
+		    (_("%pB: relocation %s against absolute symbol `%s' can "
+		       "not be used when making a shared object"),
+		     abfd, r_t ? r_t->name : _("<unknown>"), name);
+		  bfd_set_error (bfd_error_bad_value);
+		  return false;
+		}
+	    }
 	  /* Fall through.  */
 
 	case R_RISCV_JAL:
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 1b2a5ce2cb2..43572c5286b 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -308,4 +308,11 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "ifunc-seperate-plt-pic"
     run_dump_test "ifunc-seperate-pcrel-pie"
     run_dump_test "ifunc-seperate-pcrel-pic"
+
+    # Tests related to mixing medany code into position-independent targets,
+    # where it's not always possible to generate correct addressing sequences.
+    run_dump_test "pcrel-reloc-rel-nopie"
+    run_dump_test "pcrel-reloc-rel-pie"
+    run_dump_test "pcrel-reloc-abs-nopie"
+    run_dump_test "pcrel-reloc-abs-pie"
 }
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-nopie.d b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-nopie.d
new file mode 100644
index 00000000000..54026388b7a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-nopie.d
@@ -0,0 +1,14 @@
+#source: pcrel-reloc.s
+#source: pcrel-reloc-abs.s
+#as: -march=rv64i -mabi=lp64
+#ld: -melf64lriscv --no-pie --no-relax
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+.*auipc.*
+.*lw.*# [0-9a-f]* <sym>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-pie.d b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-pie.d
new file mode 100644
index 00000000000..7f5eaa321f7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs-pie.d
@@ -0,0 +1,5 @@
+#source: pcrel-reloc.s
+#source: pcrel-reloc-abs.s
+#as: -march=rv64i -mabi=lp64
+#ld: -melf64lriscv --pie --no-relax
+#error: .*relocation R_RISCV_PCREL_HI20 against absolute symbol `sym' can not be used when making a shared objec.*t
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs.s b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs.s
new file mode 100644
index 00000000000..1df32a1a3fb
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-abs.s
@@ -0,0 +1,2 @@
+.global sym
+.set sym,0x8000
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-nopie.d b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-nopie.d
new file mode 100644
index 00000000000..ab2a3774cdd
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-nopie.d
@@ -0,0 +1,14 @@
+#source: pcrel-reloc.s
+#source: pcrel-reloc-rel.s
+#as: -march=rv64i -mabi=lp64
+#ld: -melf64lriscv --no-pie --no-relax
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+.*auipc.*
+.*lw.*# [0-9a-f]* <sym>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-pie.d b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-pie.d
new file mode 100644
index 00000000000..aec612d4d2c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel-pie.d
@@ -0,0 +1,14 @@
+#source: pcrel-reloc.s
+#source: pcrel-reloc-rel.s
+#as: -march=rv64i -mabi=lp64
+#ld: -melf64lriscv --pie --no-relax
+#objdump: -d
+
+.*:[ 	]+file format .*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+.*auipc.*
+.*lw.*# [0-9a-f]* <sym>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel.s b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel.s
new file mode 100644
index 00000000000..fb0e6c09f22
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc-rel.s
@@ -0,0 +1,9 @@
+.data
+# Makes sure "sym" doesn't end up at the beginning of ".data", as that makes it
+# tough to then later detect it from scripts.
+.global buf
+buf:
+    .fill 8192, 4, 1
+.global sym
+sym:
+    .fill 8192, 4, 2
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-reloc.s b/ld/testsuite/ld-riscv-elf/pcrel-reloc.s
new file mode 100644
index 00000000000..db2103bafd1
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-reloc.s
@@ -0,0 +1,5 @@
+.text
+.global _start
+_start:
+    auipc t0, %pcrel_hi(sym)
+    lw t0, %pcrel_lo(_start)(t0)
