diff options
author | Nelson Chu <nelson.chu@sifive.com> | 2020-11-17 19:39:52 -0800 |
---|---|---|
committer | Nelson Chu <nelson.chu@sifive.com> | 2020-11-21 09:41:58 +0800 |
commit | abd20cb637008da9d32018b4b03973e119388a0a (patch) | |
tree | ad7714c9a527ae258996c30a1f4dc0ee61039073 /ld | |
parent | d4087e81506bb8c7dc50cfdf318f4343f89002f9 (diff) | |
download | fsf-binutils-gdb-abd20cb637008da9d32018b4b03973e119388a0a.zip fsf-binutils-gdb-abd20cb637008da9d32018b4b03973e119388a0a.tar.gz fsf-binutils-gdb-abd20cb637008da9d32018b4b03973e119388a0a.tar.bz2 |
RISC-V: Relax PCREL to GPREL while doing other relaxations is dangerous.
I get the feedback recently that enable linker relaxations may fail to
build some program. Consider the following case,
.text
foo:
addi a0, a0, %pcrel_lo(.L2)
call foo
.L1: auipc a1, %pcrel_hi(data_g)
addi a1, a1, %pcrel_lo(.L1)
lui a2, %hi(data_g)
addi a2, a2, %lo(data_g)
lui a3, %tprel_hi(data_t)
add a3, a3, tp, %tprel_add(data_t)
addi a3, a3, %tprel_lo(data_t)
.L2: auipc a0, %pcrel_hi(data_g)
.data
.word 0x0
.global data_g
data_g: .word 0x1
.section .tbss
data_t: .word 0x0
The current ld reports `dangerous relocation error` when doing the
pcgp relaxation,
test.o: in function `foo':
(.text+0x0): dangerous relocation: %pcrel_lo missing matching %pcrel_hi
The .L2 auipc should not be removed since it is behind the corresponding
addi, so we record the information in the pcgp_relocs table to avoid
removing the auipc later. But current ld still remove it since we do not
update the pcgp_relocs table while doing other relaxations. I have two
solutions to fix the problem,
1. Update the pcgp_relocs table once we actually delete the code.
2. Add new relax pass to do the pcgp relaxations
At first I tried to do the first solution, and we need to update at
least three information - hi_sec_off of riscv_pcgp_lo_reloc, hi_sec_off
and hi_addr (symbol value) of riscv_pcgp_hi_reloc. Update the hi_sec_off
is simple, but it is more complicate to update the symbol value, since we
almost have to do parts the same works of _bfd_riscv_relax_call again in
the riscv_relax_delete_bytes to get the correct symbol value.
Compared with the first solution, the second one is more intuitive and
simple. We add a new relax pass to do the pcgp relaxations later, so
we will get all the information correctly in the _bfd_riscv_relax_call,
including the symbol value, without changing so much code. I do not see
any penalty by adding a new relax pass for now, so it should be fine
to delay the pcgp relaxations.
Besides, I have pass all riscv-gnu-toolchain regressions for this patch.
bfd/
* elfnn-riscv.c (_bfd_riscv_relax_section): Add a new relax pass
to do the pcgp relaxation later, after the lui and call relaxations,
but before the delete and alignment relaxations.
ld/
* emultempl/riscvelf.em (riscv_elf_before_allocation): Change
link_info.relax_pass from 3 to 4.
* testsuite/ld-riscv-elf/pcgp-relax.d: New testcase.
* testsuite/ld-riscv-elf/pcgp-relax.s: Likewise.
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
Diffstat (limited to 'ld')
-rw-r--r-- | ld/ChangeLog | 8 | ||||
-rw-r--r-- | ld/emultempl/riscvelf.em | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/pcgp-relax.d | 16 | ||||
-rw-r--r-- | ld/testsuite/ld-riscv-elf/pcgp-relax.s | 29 |
5 files changed, 55 insertions, 1 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index 5e81fa2..4686c59 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,11 @@ +2020-11-21 Nelson Chu <nelson.chu@sifive.com> + + * emultempl/riscvelf.em (riscv_elf_before_allocation): Change + link_info.relax_pass from 3 to 4. + * testsuite/ld-riscv-elf/pcgp-relax.d: New testcase. + * testsuite/ld-riscv-elf/pcgp-relax.s: Likewise. + * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated. + 2020-11-20 Nick Alcock <nick.alcock@oracle.com> * testsuite/ld-ctf/data-func-conflicted.d: Shrink the expected diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em index da5c934..077f976 100644 --- a/ld/emultempl/riscvelf.em +++ b/ld/emultempl/riscvelf.em @@ -42,7 +42,7 @@ riscv_elf_before_allocation (void) ENABLE_RELAXATION; } - link_info.relax_pass = 3; + link_info.relax_pass = 4; } static void diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp index 9834041..86910e6 100644 --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp @@ -62,6 +62,7 @@ proc run_dump_test_ifunc { name target output} { if [istarget "riscv*-*-*"] { run_dump_test "call-relax" + run_dump_test "pcgp-relax" run_dump_test "c-lui" run_dump_test "c-lui-2" run_dump_test "disas-jalr" diff --git a/ld/testsuite/ld-riscv-elf/pcgp-relax.d b/ld/testsuite/ld-riscv-elf/pcgp-relax.d new file mode 100644 index 0000000..dae2b62 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/pcgp-relax.d @@ -0,0 +1,16 @@ +#source: pcgp-relax.s +#ld: --relax +#objdump: -d -Mno-aliases + +.*:[ ]+file format .* + + +Disassembly of section \.text: + +0+[0-9a-f]+ <_start>: +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+a0,a0,[0-9]+ +.*:[ ]+[0-9a-f]+[ ]+jal[ ]+ra,[0-9a-f]+ <_start> +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+a1,gp,\-[0-9]+ # [0-9a-f]+ <data_g> +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+a2,gp,\-[0-9]+ # [0-9a-f]+ <data_g> +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+a3,tp,0 # 0 <data_t> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+a0,0x[0-9a-f]+ diff --git a/ld/testsuite/ld-riscv-elf/pcgp-relax.s b/ld/testsuite/ld-riscv-elf/pcgp-relax.s new file mode 100644 index 0000000..fab6a5b --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/pcgp-relax.s @@ -0,0 +1,29 @@ + .text + .globl _start +_start: + addi a0, a0, %pcrel_lo(.L2) + + call _start +.L1: + auipc a1, %pcrel_hi(data_g) + addi a1, a1, %pcrel_lo(.L1) + + lui a2, %hi(data_g) + addi a2, a2, %lo(data_g) + + lui a3, %tprel_hi(data_t) + add a3, a3, tp, %tprel_add(data_t) + addi a3, a3, %tprel_lo(data_t) + +.L2: + auipc a0, %pcrel_hi(data_g) + + .data + .word 0x0 + .globl data_g +data_g: + .word 0x1 + + .section .tbss +data_t: + .word 0x0 |