]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
RISC-V: Fix lui relaxation issue with code at address 0.
authorJim Wilson <jimw@sifive.com>
Thu, 15 Aug 2019 19:01:13 +0000 (12:01 -0700)
committerJim Wilson <jimw@sifive.com>
Thu, 15 Aug 2019 19:01:13 +0000 (12:01 -0700)
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.

bfd/ChangeLog
bfd/elfnn-riscv.c
ld/ChangeLog
ld/testsuite/ld-riscv-elf/c-lui-2.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/c-lui-2.ld [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/c-lui-2.s [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp

index ad750bcd9a29449b273ffcf8d3d5523cbba8fdc6..8e63c9b8f9d077aae4ac8ea2c84ea7e6780d92d6 100644 (file)
@@ -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
index 706dcb923f113bb9553ad7877afc09c1015c908a..d14c29e83315456356ebc83dc3a7f87749e9840a 100644 (file)
@@ -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:
index 15ea8302b65d8049b7fa1a11c755db1131245781..0366b833b7fbfbce95970a904f222b284f607b7b 100644 (file)
@@ -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 (file)
index 0000000..622c0f7
--- /dev/null
@@ -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 (file)
index 0000000..1a0596d
--- /dev/null
@@ -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 (file)
index 0000000..7aa2586
--- /dev/null
@@ -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
index bce7bfeeba124aa27dcdd3f11b7f4620d13733e0..c994a57c48ac2f2122b697001351aab96330a60a 100644 (file)
@@ -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"