Bug 24769

Summary: [RISCV] partial RELRO doesn't work: .got is not in PT_GNU_RELRO
Product: binutils Reporter: Fangrui Song <i>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: UNCONFIRMED ---    
Severity: normal CC: nelsonc1225, wilson
Priority: P2    
Version: 2.33   
Target Milestone: ---   
Host: Target: riscv*-*-*
Build: Last reconfirmed:

Description Fangrui Song 2019-07-05 02:35:04 UTC
% riscv64-linux-gnu-gcc -fuse-ld=bfd a.c -Wl,-z,relro -Wl,-Map,a.map -o a
% readelf -l a
....
   07     .preinit_array .init_array .fini_array .dynamic

Note .got is not in PT_GNU_RELRO.

In the link map, we can see that .got.plt is placed before .got, which is unusual (likely a bug).

% cat a.map
...
.got            0x0000000000002008       0x40
 *(.got.plt)
 .got.plt       0x0000000000002008       0x18 /path/to/riscv64-linux-gnu-gcc/usr/bin/../lib/gcc-cross/riscv64-linux-gnu/8/../../../../riscv64-linux-gnu/lib/Scrt1.o
 *(.igot.plt)
 *(.got)
 .got           0x0000000000002020       0x28 /path/to/riscv64-linux-gnu-gcc/usr/bin/../lib/gcc-cross/riscv64-linux-gnu/8/../../../../riscv64-linux-gnu/lib/Scrt1.o
                0x0000000000002020                _GLOBAL_OFFSET_TABLE_
 *(.igot)

The presence of .preinit_array (from Scrt1.o) is also weird.

% readelf -x .preinit_array a

Hex dump of section '.preinit_array':
  0x00001e08 00000000 00000000                   ........
Comment 1 Nelson Chu 2021-07-21 05:20:21 UTC
This should be the linker script issue.  I spend some times to see what happened, the behavior should be right, it depends on whether the targets need sdata, or wants the separate got and gotplt.

The following change is used for experiment, without testing:
diff --git a/ld/emulparams/elf64lriscv-defs.sh b/ld/emulparams/elf64lriscv-defs.sh
index 84a700a..cba3f2a 100644
--- a/ld/emulparams/elf64lriscv-defs.sh
+++ b/ld/emulparams/elf64lriscv-defs.sh
@@ -1,2 +1,5 @@
 source_sh ${srcdir}/emulparams/elf32lriscv-defs.sh
 ELFSIZE=64
+
+SEPARATE_GOTPLT="16"  #Two entries are preserved for gotplt.
+NO_SMALL_DATA=yes

And also update the __global_pointer$ in ld/emulparams/elf32lriscv-defs.sh, since we now disable the sdata, so __SDATA_BEGIN__ won't be generated.

Then I can get your expected linker script, which places the got in the relro region, and is before gotplt.

...
  .dynamic        : { *(.dynamic) }
  .got            : { *(.got) *(.igot) }
  . = DATA_SEGMENT_RELRO_END (16, .);
  .got.plt        : { *(.got.plt) *(.igot.plt) }
  .data           :
  {
    __DATA_BEGIN__ = .;
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
...

Therefore, I think the first issue could be changed to - Should we need to place the got in the relro region? And why sdata will affect the got placement?