diff options
| author | Chih-Mao Chen <pkmx.tw@gmail.com> | 2019-04-09 11:39:23 +0000 |
|---|---|---|
| committer | Chih-Mao Chen <pkmx.tw@gmail.com> | 2019-04-09 11:39:23 +0000 |
| commit | 949570ce39da590c59fecb4cd24501351aaa64fb (patch) | |
| tree | 158f41131501001a75f888943bdbd9f33ea9592c | |
| parent | 965c5812f43809826772a31b613ba56894e47627 (diff) | |
| download | bcm5719-llvm-949570ce39da590c59fecb4cd24501351aaa64fb.tar.gz bcm5719-llvm-949570ce39da590c59fecb4cd24501351aaa64fb.zip | |
[RISCV] Fix range check for HI20/LO12/RVC_LUI relocations
The code previously specified a 32-bit range for R_RISCV_HI20 and
R_RISCV_LO12_[IS], however this is incorrect as the maximum offset on
RV64 that can be formed from the immediate of lui and the displacement
of an I-type or S-type instruction is -0x80000800 to 0x7ffff7ff. There
is also the same issue with a c.lui and LO12 pair, whose actual
addressable range should be -0x20800 to 0x1f7ff.
The tests will be included in the next patch that converts all RISC-V
tests to use llvm-mc instead of yaml2obj, as assembler support has
matured enough to write tests in them.
Differential Revision: https://reviews.llvm.org/D60414
llvm-svn: 357995
| -rw-r--r-- | lld/ELF/Arch/RISCV.cpp | 25 |
1 files changed, 13 insertions, 12 deletions
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 29a5ae62204..20d0ae08530 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -88,6 +88,8 @@ static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) { void RISCV::relocateOne(uint8_t *Loc, const RelType Type, const uint64_t Val) const { + const unsigned Bits = Config->Wordsize * 8; + switch (Type) { case R_RISCV_32: write32le(Loc, Val); @@ -130,8 +132,8 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type, } case R_RISCV_RVC_LUI: { - int32_t Imm = ((Val + 0x800) >> 12); - checkUInt(Loc, Imm, 6, Type); + int64_t Imm = SignExtend64(Val + 0x800, Bits) >> 12; + checkInt(Loc, Imm, 6, Type); if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000); } else { @@ -174,8 +176,9 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type, // auipc + jalr pair case R_RISCV_CALL: { - checkInt(Loc, Val, 32, Type); - if (isInt<32>(Val)) { + int64_t Hi = SignExtend64(Val + 0x800, Bits) >> 12; + checkInt(Loc, Hi, 20, Type); + if (isInt<20>(Hi)) { relocateOne(Loc, R_RISCV_PCREL_HI20, Val); relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val); } @@ -184,26 +187,24 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type, case R_RISCV_PCREL_HI20: case R_RISCV_HI20: { - checkInt(Loc, Val, 32, Type); - uint32_t Hi = Val + 0x800; + uint64_t Hi = Val + 0x800; + checkInt(Loc, SignExtend64(Hi, Bits) >> 12, 20, Type); write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); return; } case R_RISCV_PCREL_LO12_I: case R_RISCV_LO12_I: { - checkInt(Loc, Val, 32, Type); - uint32_t Hi = Val + 0x800; - uint32_t Lo = Val - (Hi & 0xFFFFF000); + uint64_t Hi = (Val + 0x800) >> 12; + uint64_t Lo = Val - (Hi << 12); write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20)); return; } case R_RISCV_PCREL_LO12_S: case R_RISCV_LO12_S: { - checkInt(Loc, Val, 32, Type); - uint32_t Hi = Val + 0x800; - uint32_t Lo = Val - (Hi & 0xFFFFF000); + uint64_t Hi = (Val + 0x800) >> 12; + uint64_t Lo = Val - (Hi << 12); uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25; uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7; write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0); |

