diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -103,6 +103,8 @@ case ELF::R_RISCV_PCREL_LO12_I: case ELF::R_RISCV_RVC_JUMP: case ELF::R_RISCV_RVC_BRANCH: + case ELF::R_RISCV_ADD32: + case ELF::R_RISCV_SUB32: return true; } } @@ -196,6 +198,8 @@ case ELF::R_RISCV_32_PCREL: case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: + case ELF::R_RISCV_ADD32: + case ELF::R_RISCV_SUB32: return 4; case ELF::R_RISCV_GOT_HI20: // See extractValueRISCV for why this is necessary. @@ -509,6 +513,9 @@ return SignExtend64<11>(Contents >> 2); case ELF::R_RISCV_RVC_BRANCH: return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0)); + case ELF::R_RISCV_ADD32: + case ELF::R_RISCV_SUB32: + return Contents; } } @@ -668,6 +675,9 @@ switch (Type) { default: llvm_unreachable("Unknown relocation type"); + case ELF::R_RISCV_ADD32: + case ELF::R_RISCV_SUB32: + return false; case ELF::R_RISCV_JAL: case ELF::R_RISCV_CALL: case ELF::R_RISCV_CALL_PLT: @@ -858,7 +868,16 @@ } MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint64_t Type) { - llvm_unreachable("not implemented"); + assert(Arch == Triple::riscv64 && "only implemented for RISC-V"); + + switch (Type) { + default: + llvm_unreachable("not implemented"); + case ELF::R_RISCV_ADD32: + return MCBinaryExpr::Add; + case ELF::R_RISCV_SUB32: + return MCBinaryExpr::Sub; + } } #define ELF_RELOC(name, value) #name, diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -2985,7 +2985,9 @@ }; if ((ReferencedSection && refersToReorderedSection(ReferencedSection)) || - (opts::ForceToDataRelocations && checkMaxDataRelocations())) + (opts::ForceToDataRelocations && checkMaxDataRelocations()) || + // RISC-V has ADD/SUB data-to-data relocations + BC->isRISCV()) ForceRelocation = true; if (IsFromCode) { diff --git a/bolt/test/RISCV/reloc-jt.s b/bolt/test/RISCV/reloc-jt.s new file mode 100644 --- /dev/null +++ b/bolt/test/RISCV/reloc-jt.s @@ -0,0 +1,28 @@ +/// NOTE: assign section addresses explicitly to make the symbol difference +/// calculation below less fragile. +// RUN: %clang %cflags -Wl,--section-start=.text=0x1000,--section-start=.data=0x2000 -o %t %s +// RUN: llvm-bolt -o %t.bolt %t +// RUN: llvm-readelf -x .data %t.bolt | FileCheck %s + + .text + + .globl _start + .p2align 1 +_start: +.LBB0_0: + auipc a1, %pcrel_hi(.LJTI0_0) + addi a1, a1, %pcrel_lo(.LBB0_0) + lw a0, (a1) + add a0, a0, a1 + jr a0 +.LBB0_1: + ret + .size _start, .-_start + + .data +/// .LJTI0_0 = 0x2000 +/// .LBB0_1 = 0x40000e +// CHECK: Hex dump of section '.data': +// CHECK-NEXT: 0x00002000 0ee03f00 +.LJTI0_0: + .word .LBB0_1 - .LJTI0_0 diff --git a/bolt/test/RISCV/reloc-label-diff.s b/bolt/test/RISCV/reloc-label-diff.s new file mode 100644 --- /dev/null +++ b/bolt/test/RISCV/reloc-label-diff.s @@ -0,0 +1,23 @@ +// RUN: %clang %cflags -o %t %s +// RUN: llvm-bolt -o %t.bolt %t +// RUN: llvm-readelf -x .data %t.bolt | FileCheck %s + + .text + .option norvc + .globl _start + .p2align 1 +_start: + // Force BOLT into relocation mode + .reloc 0, R_RISCV_NONE + // BOLT removes this nop so the label difference is initially 8 but should be + // 4 after BOLT processes it. + nop + beq x0, x0, _test_end +_test_end: + ret + .size _start, .-_start + + .data +// CHECK: Hex dump of section '.data': +// CHECK: 0x{{.*}} 04000000 + .word _test_end - _start