RISC-V: For PCREL_LO12, fix addend handling in auipc lookup.

Message ID 20180924213816.30562-1-jimw@sifive.com
State New
Headers show
  • RISC-V: For PCREL_LO12, fix addend handling in auipc lookup.
Related show

Commit Message

Jim Wilson Sept. 24, 2018, 9:38 p.m.
This shows up in a gcc testuite run with -mexplicit-relocs and -mcmodel=medany.
Unfortunately, it requires multiple interactions to trigger, so I don't have
a simple testcase.  But the issue here is that when we have something like
	.LA0: auipc	a5,%pcrel_hi(ll)
	lw	a0,%pcrel_lo(.LA0)(a5)
	lw	a0,%pcrel_lo(.LA0+4)(a5)
The addend in .LA0+4 applies to the target address, not the address of the
auipc, so we need to be careful how we handle the addend.  When computing the
address of the auipc, to find the matching high part of the reloc, we need to
subtract the addend if was already added in.  The following patch does this.

This was tested with riscv{32,64}-{elf,linux} cross tests, with no regressions.
This also was tested with a cross gcc testsuite run for riscv32-elf, and fixes
several hundred failures.

	* elfnn-riscv.c (_bfd_riscv_relax_pc) <R_RISCV_PCREL_LO12_I>: New local
	hi_sec_off which is symbol address with addend subtracted.  Use in
	riscv_find_pcgp_hi_reloc and riscv_record_pcgp_lo_reloc calls.
 bfd/elfnn-riscv.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)



diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 63ff07e13a..f3e2cc7c37 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3226,11 +3226,16 @@  _bfd_riscv_relax_pc  (bfd *abfd,
     case R_RISCV_PCREL_LO12_I:
     case R_RISCV_PCREL_LO12_S:
+	/* If the %lo has an addend, it isn't for the label pointing at the
+	   hi part instruction, but rather for the symbol pointed at by the
+	   hi part instruction.  So we must subtract it here for the lookup.
+	   It is still used below in the final symbol address.  */
+	bfd_vma hi_sec_off = symval - sec_addr (sym_sec) - rel->r_addend;
 	riscv_pcgp_hi_reloc *hi = riscv_find_pcgp_hi_reloc (pcgp_relocs,
-							    symval - sec_addr(sym_sec));
+							    hi_sec_off);
 	if (hi == NULL)
-	    riscv_record_pcgp_lo_reloc (pcgp_relocs, symval - sec_addr(sym_sec));
+	    riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off);
 	    return TRUE;