[PATCH 1/3] RISC-V: Allow to generate RELATIVE in got if pie and sections of GOT_HO20 are all discared

Nelson Chu nelson@rivosinc.com
Sat Jun 7 08:36:39 GMT 2025


This happened when I was porting the relr stuff, and caused problem for
relr-discard testcases.  Considering there is an got entry needs an dynamic
RELATIVE relocation when pie, we used to have an assert to make sure that the
h->got.offset was marked as done in the relocate_section function.  But if the
sections of related GOT_HO20 are all discared by linker script, all related
GOT_HI20 will be skipped and converted to R_RISCV_NONE in the relocate_section,
so that the h->got.offset won't be marked as done, and then break the link.

According to the relr-discard testcases of aarch64 and loongarch, it seems
still need to generate a dynamic RELATIVE for this case.  The loongarch seems
doesn't have the assert, but aarch64 and x86 have.  I don't know how it works
with the assert check for this case, so I just ignore the assert until someone
clarify and figure it out.
---
 bfd/elfnn-riscv.c                          | 17 ++++-
 ld/testsuite/ld-riscv-elf/discard-pic.d    | 15 +++++
 ld/testsuite/ld-riscv-elf/discard-pie.d    | 15 +++++
 ld/testsuite/ld-riscv-elf/discard.ld       | 13 ++++
 ld/testsuite/ld-riscv-elf/discard.s        | 75 ++++++++++++++++++++++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  3 +
 6 files changed, 135 insertions(+), 3 deletions(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/discard-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/discard-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/discard.ld
 create mode 100644 ld/testsuite/ld-riscv-elf/discard.s

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 1c494f5f986..db9372c2b10 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3446,9 +3446,20 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
 	  /* If this is a local symbol reference, we just want to emit
 	     a RELATIVE reloc.  This can happen if it is a -Bsymbolic link,
 	     or a pie link, or the symbol was forced to be local because
-	     of a version file.  The entry in the global offset table will
-	     already have been initialized in the relocate_section function.  */
-	  BFD_ASSERT ((h->got.offset & 1) != 0);
+	     of a version file.  The entry in the global offset table "should"
+	     already have been initialized in the relocate_section function,
+	     except the sections of the related relocation are all discarded.  */
+
+	  /* If the sections of the related relocation are all discarded, then
+	     the RELOC_AGAINST_DISCARDED_SECTION cleans all related relocation
+	     to R_RISCV_NONE in the relocate_section, so the h->got.offset will
+	     not be marked as done in the relocate_section function.  In this
+	     case most of the targets seems still generate a RELATIVE reloc,
+	     but I don't know how that works with the following assert, so just
+	     ignore it until someone clarify and figure this out.
+
+	  BFD_ASSERT ((h->got.offset & 1) != 0);  */
+
 	  asection *sec = h->root.u.def.section;
 	  rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
 	  rela.r_addend = (h->root.u.def.value
diff --git a/ld/testsuite/ld-riscv-elf/discard-pic.d b/ld/testsuite/ld-riscv-elf/discard-pic.d
new file mode 100644
index 00000000000..f876cdf06ba
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/discard-pic.d
@@ -0,0 +1,15 @@
+#source: discard.s
+#as: -march=rv64i -mabi=lp64
+#ld: -shared -T discard.ld -melf64lriscv
+#readelf: -rW
+
+Relocation section '\.rela\.dyn'.*
+[ 	]+Offset[ 	]+Info[ 	]+Type.*
+0000000000020010[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0000000000020018[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global \+ 0
+0000000000020020[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global_keep \+ 0
diff --git a/ld/testsuite/ld-riscv-elf/discard-pie.d b/ld/testsuite/ld-riscv-elf/discard-pie.d
new file mode 100644
index 00000000000..4e0d8cfb495
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/discard-pie.d
@@ -0,0 +1,15 @@
+#source: discard.s
+#as: -march=rv64i -mabi=lp64
+#ld: -pie -T discard.ld -melf64lriscv
+#readelf: -rW
+
+Relocation section '\.rela\.dyn'.*
+[ 	]+Offset[ 	]+Info[ 	]+Type.*
+0000000000020010[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+0000000000020018[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+1000c
+0000000000020020[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+1000c
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
+0+0[ 	]+0+0[ 	]+R_RISCV_NONE[ 	]+0
diff --git a/ld/testsuite/ld-riscv-elf/discard.ld b/ld/testsuite/ld-riscv-elf/discard.ld
new file mode 100644
index 00000000000..3afed216fbc
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/discard.ld
@@ -0,0 +1,13 @@
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+  /DISCARD/ : { *(.discard.*) }
+
+  . = 0x10000;
+  .text : { *(.text) }
+  . = 0x20000;
+  .got  : { *(.got) *(.got.plt)}
+  . = 0x30000;
+  .data : { *(.data) *(.data.*) }
+}
diff --git a/ld/testsuite/ld-riscv-elf/discard.s b/ld/testsuite/ld-riscv-elf/discard.s
new file mode 100644
index 00000000000..729a5f9995a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/discard.s
@@ -0,0 +1,75 @@
+.text
+.option pic
+.p2align 3
+.global _start
+_start:
+	nop
+
+sym_local:
+sym_local_keep:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+.global sym_global_keep
+sym_global:
+sym_global_keep:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
+
+.section .got_local_keep,"ax"
+        la      x1, sym_local_keep
+.section .discard.got_local_keep,"ax"
+	la	x1, sym_local_keep
+
+.section .got_global_keep,"ax"
+        la      x1, sym_global_keep
+.section .discard.got_global_keep,"ax"
+	la	x1, sym_global_keep
+
+# All relocation refer to sym_local are discarded.
+.section .discard.got_local,"ax"
+	la	x1, sym_local
+
+# All relocation refer to sym_global are discarded.
+.section .discard.got_global,"ax"
+	la	x1, sym_global
+
+.section .discard.local,"a"
+.p2align 1
+discard_local:
+.quad sym_local
+
+.section .discard.hidden,"a"
+.p2align 1
+discard_hidden:
+.quad sym_hidden
+
+.section .discard.global,"a"
+.p2align 1
+discard_global:
+.quad sym_global
+
+.section .discard.global_abs,"a"
+.p2align 1
+discard_global_abs:
+.quad sym_global_abs
+
+.section .discard.weak_undef,"a"
+.p2align 1
+discard_weak_undef:
+.quad sym_weak_undef
+
+.section .discard._DYNAMIC,"a"
+.p2align 1
+discard_DYNAMIC:
+.quad _DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 9cb847d3d8a..d68a9145dcd 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -227,6 +227,9 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "data-reloc-rv64-addr32-pic"
     run_dump_test "data-reloc-rv64-undef32-pic"
 
+    run_dump_test "discard-pie"
+    run_dump_test "discard-pic"
+
     # IFUNC testcases.
     # Check IFUNC by single type relocs.
     run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
-- 
2.39.5 (Apple Git-154)



More information about the Binutils mailing list