diff options
author | Jim Wilson <jimw@sifive.com> | 2019-08-15 12:01:13 -0700 |
---|---|---|
committer | Jim Wilson <jimw@sifive.com> | 2019-08-15 12:01:13 -0700 |
commit | 080a488354d63fec9791a26fadd15e0c5246983d (patch) | |
tree | 9aa728d8b99659e38b8f1eb05a128c8e60e74cb9 /bfd/elfnn-riscv.c | |
parent | db502012fc46b4dd068461aaeafeaa421489c562 (diff) | |
download | binutils-gdb-080a488354d63fec9791a26fadd15e0c5246983d.tar.gz |
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.
Diffstat (limited to 'bfd/elfnn-riscv.c')
-rw-r--r-- | bfd/elfnn-riscv.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 706dcb923f1..d14c29e8331 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: |