RISC-V: PR27566, Do not relax when data segment phase is exp_seg_relro_adjust.
authorNelson Chu <nelson.chu@sifive.com>
Wed, 12 May 2021 15:26:33 +0000 (08:26 -0700)
committerNelson Chu <nelson.chu@sifive.com>
Mon, 31 May 2021 03:29:26 +0000 (11:29 +0800)
2021-05-31  Nelson Chu  <nelson.chu@sifive.com>
            Lifang Xia  <lifang_xia@c-sky.com>

The data segment phase exp_seg_relro_adjust means we are still adjusting the
relro segments, so we will get the symbol values which havn't consider the
relro.  It is dangerous and we shouldn't do the relaxations at this stage.
Otherwise, we may get the truncated fails when the relax range crossing the
data segment.

One of the solution is that, we use a pointer to monitor the data segment
phase while relaxing, to know whether the relro has been handled or not.
Once we check the phase is exp_seg_relro_adjust, we should skip this round
of relaxations, since the incorrect symbol values will affect the correctness
of relaxations.  I think we probably need to record more information about
data segment or alignments in the future, to make sure it is safe to doing
relaxations.

For the two new testcases, relro-relax-lui and relro-relax-pcrel, we get
the following truncated errors when using toolchains, which enable relro:

(.text+0x0): relocation truncated to fit: R_RISCV_GPREL_I against symbol `SymbolRodata' defined in .rodata section in test1.o

After applying this patch, the truncated errors should be resolved.
However, only linux toolchains support -z relro, so we only test these
two testcases when supporting shared library.

bfd/
    PR 27566
    * elfnn-riscv.c (struct riscv_elf_link_hash_table): New integer pointer
    to monitor the data segment phase.
    (bfd_elfNN_riscv_set_data_segment_info): New function called by
    after_allocation, to set the data_segment_phase from expld.dataseg.
    (_bfd_riscv_relax_section): Don't relax when data_segment_phase is
    exp_seg_relro_adjust (0x4).
    * elfxx-riscv.h (bfd_elf32_riscv_set_data_segment_info): New extern.
    (bfd_elf64_riscv_set_data_segment_info): Likewise.
ld/
    PR 27566
    * emultempl/riscvelf.em (after_allocation): Call
    riscv_set_data_segment_info to set data segment phase before relaxing.
    * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
    * testsuite/ld-riscv-elf/relro-relax-lui.d: New testcase.
    * testsuite/ld-riscv-elf/relro-relax-lui.s: Likewise.
    * testsuite/ld-riscv-elf/relro-relax-pcrel.d: Likewise.
    * testsuite/ld-riscv-elf/relro-relax-pcrel.s: Likewise.

bfd/ChangeLog
bfd/elfnn-riscv.c
bfd/elfxx-riscv.h
ld/ChangeLog
ld/emultempl/riscvelf.em
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
ld/testsuite/ld-riscv-elf/relro-relax-lui.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/relro-relax-lui.s [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/relro-relax-pcrel.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/relro-relax-pcrel.s [new file with mode: 0644]

index 6242f3c76c7e0d72eb9f8846ae3fcf28299a2ede..fd9721e7809b8b02f9417dab96d670038ac3bf11 100644 (file)
@@ -1,3 +1,16 @@
+2021-05-31  Nelson Chu  <nelson.chu@sifive.com>
+           Lifang Xia  <lifang_xia@c-sky.com>
+
+       PR 27566
+       * elfnn-riscv.c (struct riscv_elf_link_hash_table): New integer pointer
+       to monitor the data segment phase.
+       (bfd_elfNN_riscv_set_data_segment_info): New function called by
+       after_allocation, to set the data_segment_phase from expld.dataseg.
+       (_bfd_riscv_relax_section): Don't relax when data_segment_phase is
+       exp_seg_relro_adjust (0x4).
+       * elfxx-riscv.h (bfd_elf32_riscv_set_data_segment_info): New extern.
+       (bfd_elf64_riscv_set_data_segment_info): Likewise
+
 2021-05-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/27905
index d2781f3099350859d413cb855d034d90d17d3b17..eef1e800221ac25a2435b0370b8d03e4cc1d21dd 100644 (file)
@@ -132,6 +132,10 @@ struct riscv_elf_link_hash_table
 
   /* Re-run the relaxations from relax pass 0 if TRUE.  */
   bool restart_relax;
+
+  /* The data segment phase, don't relax the section
+     when it is exp_seg_relro_adjust.  */
+  int *data_segment_phase;
 };
 
 /* Instruction access functions. */
@@ -4620,6 +4624,17 @@ _bfd_riscv_relax_delete (bfd *abfd,
   return true;
 }
 
+/* Called by after_allocation to set the information of data segment
+   before relaxing.  */
+
+void
+bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info,
+                                       int *data_segment_phase)
+{
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  htab->data_segment_phase = data_segment_phase;
+}
+
 /* Called by after_allocation to check if we need to run the whole
    relaxations again.  */
 
@@ -4672,7 +4687,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
       || (info->disable_target_specific_optimizations
          && info->relax_pass < 2)
       || (htab->restart_relax
-         && info->relax_pass == 3))
+         && info->relax_pass == 3)
+      /* The exp_seg_relro_adjust is enum phase_enum (0x4),
+        and defined in ld/ldexp.h.  */
+      || *(htab->data_segment_phase) == 4)
     return true;
 
   riscv_init_pcgp_relocs (&pcgp_relocs);
index c2fff92608624f71406b0ca66a1f6c8e2a6a910f..6a2501b7be80065e4531b7fd91b3d004d6eb5f00 100644 (file)
@@ -98,6 +98,10 @@ riscv_compare_subsets (const char *, const char *);
 
 extern bool
 bfd_elf32_riscv_restart_relax_sections (struct bfd_link_info *);
-
 extern bool
 bfd_elf64_riscv_restart_relax_sections (struct bfd_link_info *);
+
+extern void
+bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
+extern void
+bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
index 263dee0305994f029d47129fc12fe60b800d6078..2c6615d46c8d667bbd3f31d97787057af22b7a49 100644 (file)
@@ -1,3 +1,15 @@
+2021-05-31  Nelson Chu  <nelson.chu@sifive.com>
+           Lifang Xia  <lifang_xia@c-sky.com>
+
+       PR 27566
+       * emultempl/riscvelf.em (after_allocation): Call
+       riscv_set_data_segment_info to set data segment phase before relaxing.
+       * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
+       * testsuite/ld-riscv-elf/relro-relax-lui.d: New testcase.
+       * testsuite/ld-riscv-elf/relro-relax-lui.s: Likewise.
+       * testsuite/ld-riscv-elf/relro-relax-pcrel.d: Likewise.
+       * testsuite/ld-riscv-elf/relro-relax-pcrel.s: Likewise.
+
 2021-05-28  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/27905
index 5fa7c773fc88f94f3bc6efa5c7bbf88ebe2201ab..c625a631fe52b2bacd5d1f3e0561a1b952abdd57 100644 (file)
@@ -62,6 +62,20 @@ gld${EMULATION_NAME}_after_allocation (void)
        }
     }
 
+  /* PR 27566, if the phase of data segment is exp_seg_relro_adjust,
+     that means we are still adjusting the relro, and shouldn't do the
+     relaxations at this stage.  Otherwise, we will get the symbol
+     values beofore handling the relro, and may cause truncated fails
+     when the relax range crossing the data segment.  One of the solution
+     is to monitor the data segment phase while relaxing, to know whether
+     the relro has been handled or not.
+
+     I think we probably need to record more information about data
+     segment or alignments in the future, to make sure it is safe
+     to doing relaxations.  */
+  enum phase_enum *phase = &(expld.dataseg.phase);
+  bfd_elf${ELFSIZE}_riscv_set_data_segment_info (&link_info, (int *) phase);
+
   do
     {
       ldelf_map_segments (need_layout);
index 319ac7e2b836ee0cdc10a2bb08f8f538df9395a7..0b49ddcacf607dcebf8d6deed4766ef65e4d822a 100644 (file)
@@ -122,6 +122,9 @@ if [istarget "riscv*-*-*"] {
        return
     }
 
+    run_dump_test "relro-relax-lui"
+    run_dump_test "relro-relax-pcrel"
+
     set abis [list rv32gc ilp32 [riscv_choose_ilp32_emul] rv64gc lp64 [riscv_choose_lp64_emul]]
     foreach { arch abi emul } $abis {
        # This checks whether our linker scripts handle __global_pointer$
diff --git a/ld/testsuite/ld-riscv-elf/relro-relax-lui.d b/ld/testsuite/ld-riscv-elf/relro-relax-lui.d
new file mode 100644 (file)
index 0000000..d29aa9d
--- /dev/null
@@ -0,0 +1,12 @@
+#source: relro-relax-lui.s
+#ld: -zrelro --relax
+#objdump: -d -Mno-aliases
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+[0-9a-f]+ <_start>:
+.*:[   ]+[0-9a-f]+[    ]+lui[  ]+.*
+.*:[   ]+[0-9a-f]+[    ]+addi[         ]+.*<SymbolRodata>
diff --git a/ld/testsuite/ld-riscv-elf/relro-relax-lui.s b/ld/testsuite/ld-riscv-elf/relro-relax-lui.s
new file mode 100644 (file)
index 0000000..f284187
--- /dev/null
@@ -0,0 +1,15 @@
+       .section        .rodata
+       .align  10
+       .globl  SymbolRodata
+       .set    SymbolRodata, . + 0x1800
+       .word   0x0
+
+
+       .section        .init_array
+        .word  0x0
+
+       .text
+       .globl  _start
+_start:
+       lui     a0, %hi (SymbolRodata)
+       addi    a0, a0, %lo (SymbolRodata)
diff --git a/ld/testsuite/ld-riscv-elf/relro-relax-pcrel.d b/ld/testsuite/ld-riscv-elf/relro-relax-pcrel.d
new file mode 100644 (file)
index 0000000..28e11b3
--- /dev/null
@@ -0,0 +1,12 @@
+#source: relro-relax-pcrel.s
+#ld: -zrelro --relax
+#objdump: -d -Mno-aliases
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+[0-9a-f]+ <_start>:
+.*:[   ]+[0-9a-f]+[    ]+auipc[        ]+.*
+.*:[   ]+[0-9a-f]+[    ]+addi[         ]+.*<SymbolRodata>
diff --git a/ld/testsuite/ld-riscv-elf/relro-relax-pcrel.s b/ld/testsuite/ld-riscv-elf/relro-relax-pcrel.s
new file mode 100644 (file)
index 0000000..4a88287
--- /dev/null
@@ -0,0 +1,14 @@
+       .section        .rodata
+       .align  10
+       .globl  SymbolRodata
+       .set    SymbolRodata, . + 0x1800
+       .word   0x0
+
+
+       .section        .init_array
+        .word  0x0
+
+       .text
+       .globl  _start
+_start:
+       lla     a0, SymbolRodata