aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Wilson <jimw@sifive.com>2019-08-15 12:01:13 -0700
committerJim Wilson <jimw@sifive.com>2019-08-15 12:01:13 -0700
commit080a488354d63fec9791a26fadd15e0c5246983d (patch)
tree9aa728d8b99659e38b8f1eb05a128c8e60e74cb9
parentdb502012fc46b4dd068461aaeafeaa421489c562 (diff)
downloadbinutils-080a488354d63fec9791a26fadd15e0c5246983d.zip
binutils-080a488354d63fec9791a26fadd15e0c5246983d.tar.gz
binutils-080a488354d63fec9791a26fadd15e0c5246983d.tar.bz2
RISC-V: Fix lui relaxation issue with code at address 0.
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. 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.
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elfnn-riscv.c16
-rw-r--r--ld/ChangeLog7
-rw-r--r--ld/testsuite/ld-riscv-elf/c-lui-2.d19
-rw-r--r--ld/testsuite/ld-riscv-elf/c-lui-2.ld6
-rw-r--r--ld/testsuite/ld-riscv-elf/c-lui-2.s12
-rw-r--r--ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp1
7 files changed, 65 insertions, 2 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index ad750bc..8e63c9b 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,9 @@
+2019-08-15 Jim Wilson <jimw@sifive.com>
+
+ * 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.
+
2019-08-15 Tom Tromey <tromey@adacore.com>
* dwarf2.c (scan_unit_for_symbols): Check for end of CU, not end
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 706dcb9..d14c29e 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/ChangeLog b/ld/ChangeLog
index 15ea830..0366b83 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,10 @@
+2019-08-15 Jim Wilson <jimw@sifive.com>
+
+ * 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.
+
2019-08-10 Alan Modra <amodra@gmail.com>
* ldlang.h (enum statement_enum): Sort.
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 0000000..622c0f7a
--- /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 0000000..1a0596d
--- /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 0000000..7aa2586
--- /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 bce7bfe..c994a57 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"