RISC-V: PR27566, Do not relax when data segment phase is exp_seg_relro_adjust.

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.
This commit is contained in:
Nelson Chu 2021-05-12 08:26:33 -07:00
parent cc653233da
commit ef9d256562
10 changed files with 119 additions and 2 deletions

View 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

View 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);

View 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 *);

View 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

View 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);

View 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$

View File

@ -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>

View File

@ -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)

View File

@ -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>

View File

@ -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