RISC-V: Fix lui relaxation issue with code at address 0.

Message ID 20190815190359.15226-1-jimw@sifive.com
State New
Headers show
Series
  • RISC-V: Fix lui relaxation issue with code at address 0.
Related show

Commit Message

Jim Wilson Aug. 15, 2019, 7:03 p.m.
This fixes a problem originally reported at
    https://github.com/riscv/riscv-binutils-gdb/issues/173

If you have code linked at address zero, you can have a lui instruction
loading a value 0x800 which gets relaxed to a c.lui which is valid (c.lui 0x1
followed by addi -0x800).  Relaxation can reduce the value below 0x800 at which
point the c.lui 0x0 is no longer valid.  We can fix this by converting the
c.lui to a c.li which can load 0.

This was triggered by the changes from Optimitech to enable relaxation in
code and merge sections.

This patch adds a new testcase, since normally we don't link at address 0 by
default.  The new test fails without the patch, and works with the patch.

This was tested with a cross gcc make check for 32-bit elf and 64-bit linux,
and cross binutils make check for 32/64 elf/linux.  There were no regressions.

Committed.

Jim

	bfd/
	* elfnn-riscv.c (perform_relocation) <R_RISCV_RVC_LUI>: If
	RISCV_CONST_HIGH_PART (value) is zero, then convert c.lui instruction
	to c.li instruction, and use ENCODE_RVC_IMM to set value.

	ld/
	* testsuite/ld-riscv-elf/c-lui-2.d: New.
	* testsuite/ld-riscv-elf/c-lui-2.ld: New.
	* testsuite/ld-riscv-elf/c-lui-2.s: New.
	* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Run the c-lui-2 test.
---
 bfd/elfnn-riscv.c                          | 16 ++++++++++++++--
 ld/testsuite/ld-riscv-elf/c-lui-2.d        | 19 +++++++++++++++++++
 ld/testsuite/ld-riscv-elf/c-lui-2.ld       |  6 ++++++
 ld/testsuite/ld-riscv-elf/c-lui-2.s        | 12 ++++++++++++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp |  1 +
 5 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/c-lui-2.d
 create mode 100644 ld/testsuite/ld-riscv-elf/c-lui-2.ld
 create mode 100644 ld/testsuite/ld-riscv-elf/c-lui-2.s

-- 
2.17.1

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 706dcb923f..d14c29e833 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1482,9 +1482,21 @@  perform_relocation (const reloc_howto_type *howto,
       break;
 
     case R_RISCV_RVC_LUI:
-      if (!VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
+      if (RISCV_CONST_HIGH_PART (value) == 0)
+	{
+	  /* Linker relaxation can convert an address equal to or greater than
+	     0x800 to slightly below 0x800.  C.LUI does not accept zero as a
+	     valid immediate.  We can fix this by converting it to a C.LI.  */
+	  bfd_vma insn = bfd_get (howto->bitsize, input_bfd,
+				  contents + rel->r_offset);
+	  insn = (insn & ~MATCH_C_LUI) | MATCH_C_LI;
+	  bfd_put (howto->bitsize, input_bfd, insn, contents + rel->r_offset);
+	  value = ENCODE_RVC_IMM (0);
+	}
+      else if (!VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
 	return bfd_reloc_overflow;
-      value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
+      else
+	value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
     case R_RISCV_32:
diff --git a/ld/testsuite/ld-riscv-elf/c-lui-2.d b/ld/testsuite/ld-riscv-elf/c-lui-2.d
new file mode 100644
index 0000000000..622c0f7a31
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/c-lui-2.d
@@ -0,0 +1,19 @@ 
+#name: c.lui to c.li relaxation
+#source: c-lui-2.s
+#as: -march=rv32ic
+#ld: -melf32lriscv -Tc-lui-2.ld
+#objdump: -d -M no-aliases,numeric
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+.*:	4501                	c.li	x10,0
+.*:	7fe00513          	addi	x10,x0,2046
+	...
+
+.* <foo>:
+.*:	8082                	c.jr	x1
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/c-lui-2.ld b/ld/testsuite/ld-riscv-elf/c-lui-2.ld
new file mode 100644
index 0000000000..1a0596dad9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/c-lui-2.ld
@@ -0,0 +1,6 @@ 
+ENTRY(_start)
+SECTIONS {
+	.text 0x00000000 : {
+		*(.text*)
+	}
+}
diff --git a/ld/testsuite/ld-riscv-elf/c-lui-2.s b/ld/testsuite/ld-riscv-elf/c-lui-2.s
new file mode 100644
index 0000000000..7aa258606a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/c-lui-2.s
@@ -0,0 +1,12 @@ 
+	.option nopic
+	.text
+	.align 1
+	.globl _start
+	.type _start, @function
+_start:
+	lui a0,%hi(foo)
+	addi a0,a0,%lo(foo)
+	.skip 0x7f8
+foo:
+	ret
+	.size _start, .-_start
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index bce7bfeeba..c994a57c48 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -21,6 +21,7 @@ 
 
 if [istarget "riscv*-*-*"] {
     run_dump_test "c-lui"
+    run_dump_test "c-lui-2"
     run_dump_test "disas-jalr"
     run_dump_test "pcrel-lo-addend"
     run_dump_test "pcrel-lo-addend-2"