LoongArch: overflow and underflow checks for R_LARCH_32_PCREL

Relocation overflows can silently write incorrect value to
the file, so overflow checks are added to avoid this.
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index faad512..5c504f2 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -2933,11 +2933,21 @@
       {
 	value -= sec_addr (input_section) + rel->r_offset;
 	value += rel->r_addend;
-	bfd_vma word = bfd_get (howto->bitsize, input_bfd,
-				contents + rel->r_offset);
-	word = (word & ~howto->dst_mask) | (value & howto->dst_mask);
-	bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset);
-	r = bfd_reloc_ok;
+	/* Check overflow.  */
+	if (ELFNN_R_TYPE (rel->r_info) == R_LARCH_32_PCREL)
+	  {
+	    r = loongarch_reloc_rewrite_imm_insn (rel, input_section,
+						  howto, input_bfd,
+						  contents, value);
+	  }
+	else
+	  {
+	    bfd_vma word = bfd_get (howto->bitsize, input_bfd,
+				    contents + rel->r_offset);
+	    word = (word & ~howto->dst_mask) | (value & howto->dst_mask);
+	    bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset);
+	    r = bfd_reloc_ok;
+	  }
 	break;
       }
 
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index 182617b..6268c47 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -1390,7 +1390,7 @@
 	 0xffffffff,				/* dst_mask */
 	 false,					/* pcrel_offset */
 	 BFD_RELOC_LARCH_32_PCREL,		/* bfd_reloc_code_real_type */
-	 NULL,					/* adjust_reloc_bits */
+	 reloc_sign_bits,			/* adjust_reloc_bits */
 	 NULL),					/* larch_reloc_type_name */
 
   /* The paired relocation may be relaxed.  */
diff --git a/ld/testsuite/ld-loongarch-elf/32_pcrel.s b/ld/testsuite/ld-loongarch-elf/32_pcrel.s
new file mode 100644
index 0000000..3ef16de
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/32_pcrel.s
@@ -0,0 +1,6 @@
+	.section sx,"a"
+x:
+	nop
+
+	.section sy,"a"
+	.4byte x-.
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 0295be8..2f09a69 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -200,6 +200,8 @@
     run_dump_test "bad_pcrel20_s2_global"
     run_dump_test "bad_pcrel20_s2_weak"
     run_dump_test "weak-undef-hidden-shared"
+    run_dump_test "overflow_32_pcrel"
+    run_dump_test "underflow_32_pcrel"
   }
 
   if [check_pie_support] {
diff --git a/ld/testsuite/ld-loongarch-elf/overflow_32_pcrel.d b/ld/testsuite/ld-loongarch-elf/overflow_32_pcrel.d
new file mode 100644
index 0000000..154dac9
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/overflow_32_pcrel.d
@@ -0,0 +1,4 @@
+#source: 32_pcrel.s
+#as: -mthin-add-sub
+#ld: -shared --section-start=sx=0x80001000 --section-start=sy=0x1000
+#error: .*relocation truncated to fit: R_LARCH_32_PCREL against `x'
diff --git a/ld/testsuite/ld-loongarch-elf/underflow_32_pcrel.d b/ld/testsuite/ld-loongarch-elf/underflow_32_pcrel.d
new file mode 100644
index 0000000..a5396bc
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/underflow_32_pcrel.d
@@ -0,0 +1,4 @@
+#source: 32_pcrel.s
+#as: -mthin-add-sub
+#ld: -shared --section-start=sx=0x1000 --section-start=sy=0x80001001
+#error: .*relocation truncated to fit: R_LARCH_32_PCREL against `x'