From 080a488354d63fec9791a26fadd15e0c5246983d Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Thu, 15 Aug 2019 12:01:13 -0700 Subject: [PATCH] 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) : 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 | 6 ++++++ bfd/elfnn-riscv.c | 16 ++++++++++++++-- ld/ChangeLog | 7 +++++++ 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 + 7 files changed, 65 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 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 + + * elfnn-riscv.c (perform_relocation) : 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 * 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 + + * 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 * 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 + ... + +.* : +.*: 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" -- 2.7.4