Index: llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h =================================================================== --- llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -60,6 +60,10 @@ void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); + void resolveRISCVRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + SID SectionID); + unsigned getMaxStubSize() const override { if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) return 20; // movz; movk; movk; movk; br @@ -150,6 +154,10 @@ // *LO16 part. (Mips specific) SmallVector, 8> PendingRelocs; + // Mapping from *HI20 relocations to their PC-relative target. Used to resolve + // the corresponding *LO12 relocations. RISC-V specific. + SmallVector, 8> PCRelHIRelocs; + // When a module is loaded we save the SectionID of the EH frame section // in a table until we receive a request to register all unregistered // EH frame sections with the memory manager. Index: llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp =================================================================== --- llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1007,6 +1007,79 @@ } } +static void applyUpperImmRISCV(uint8_t *InstrAddr, uint32_t Imm) { + uint32_t UpperImm = (Imm + 0x800) & 0xfffff000; + auto Instr = support::ulittle32_t::ref(InstrAddr); + Instr = (Instr & 0xfff) | UpperImm; +} + +static void applyLowerImmRISCV(uint8_t *InstrAddr, uint32_t Imm) { + uint32_t LowerImm = Imm & 0xfff; + auto Instr = support::ulittle32_t::ref(InstrAddr); + Instr = (Instr & 0xfffff) | (LowerImm << 20); +} + +void RuntimeDyldELF::resolveRISCVRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + SID SectionID) { + switch (Type) { + default: + llvm_unreachable("unimplemented reloc"); + case ELF::R_RISCV_CALL: + case ELF::R_RISCV_CALL_PLT: { + uint64_t PC = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - PC; + applyUpperImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + applyLowerImmRISCV(Section.getAddressWithOffset(Offset + 4), PCOffset); + break; + } + case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_PCREL_HI20: { + uint64_t PC = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - PC; + applyUpperImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + auto ValueRef = RelocationValueRef{SectionID, Offset}; + PCRelHIRelocs.push_back(std::make_pair(ValueRef, PCOffset)); + break; + } + case ELF::R_RISCV_PCREL_LO12_I: { + uint64_t HIOffset = Addend; + + for (auto I = PCRelHIRelocs.begin(), E = PCRelHIRelocs.end(); I != E; ++I) { + auto &Rel = I->first; + + if (Rel.SectionID == SectionID && Rel.Offset == HIOffset) { + auto PCOffset = I->second; + applyLowerImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + return; + } + } + + llvm_unreachable( + "R_RISCV_PCREL_LO12_I without matching R_RISCV_PCREL_HI20"); + } + case ELF::R_RISCV_32_PCREL: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t RealOffset = Value + Addend - FinalAddress; + int32_t TruncOffset = (RealOffset & 0xffffffff); + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + TruncOffset; + break; + } + case ELF::R_RISCV_ADD32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_SUB32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref - Value - Addend; + break; + } + } +} + // The target location for the relocation is described by RE.SectionID and // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each // SectionEntry has three members describing its location. @@ -1072,6 +1145,10 @@ case Triple::bpfeb: resolveBPFRelocation(Section, Offset, Value, Type, Addend); break; + case Triple::riscv32: + case Triple::riscv64: + resolveRISCVRelocation(Section, Offset, Value, Type, Addend, SectionID); + break; default: llvm_unreachable("Unsupported CPU type!"); } Index: llvm/test/ExecutionEngine/RuntimeDyld/RISCV/ELF_RISCV_relocations.s =================================================================== --- /dev/null +++ llvm/test/ExecutionEngine/RuntimeDyld/RISCV/ELF_RISCV_relocations.s @@ -0,0 +1,47 @@ +# RUN: rm -rf %t && mkdir -p %t +# RUN: llvm-mc -triple=riscv64-linux-elf -filetype=obj -o %t/reloc.o %s +# RUN: llvm-rtdyld -triple=riscv64-linux-elf -verify -dummy-extern f=0x12345678 -dummy-extern d=0xabcdef12 -check=%s %t/reloc.o + +# RUN: rm -rf %t && mkdir -p %t +# RUN: llvm-mc -triple=riscv32-linux-elf -filetype=obj -o %t/reloc.o %s +# RUN: llvm-rtdyld -triple=riscv32-linux-elf -verify -dummy-extern f=0x12345678 -dummy-extern d=0xabcdef12 -check=%s %t/reloc.o + + .skip 0x1234 + .p2align 2 +g: +# R_RISCV_CALL_PLT + call f + +h: +# R_RISCV_PCREL_HI20 +# R_RISCV_PCREL_LO12_I + la t0, d + +a: +# R_RISCV_ADD32 +# R_RISCV_SUB32 + .word h-g + +b: +# R_RISCV_32_PCREL + .cfi_startproc + nop + .cfi_endproc + +## Check R_RISCV_CALL_PLT +# rtdyld-check: (*{4}g)[31:12] = (f-g+0x800)[31:12] +# rtdyld-check: (*{4}(g+4))[31:20] = (f-g)[11:0] + +## Check R_RISCV_PCREL_HI20 +# rtdyld-check: (*{4}h)[31:12] = (d-h+0x800)[31:12] + +## Check R_RISCV_PCREL_LO12_I +# rtdyld-check: (*{4}(h+4))[31:20] = (d-h)[11:0] + +## Check R_RISCV_ADD32 and R_RISCV_SUB32 +# rtdyld-check: *{4}a = (h-g) + +## Check R_RISCV_32_PCREL added to .eh_frame+0x1c +## NOTE disabled because unnamed symbols in .eh_frame do not get resolved +## rtdyld-check: *{4}(section_addr(reloc.o, .eh_frame) + 0x1c) = (b - (section_addr(reloc.o, .eh_frame) + 0x1c))[31:0] + Index: llvm/test/ExecutionEngine/RuntimeDyld/RISCV/lit.local.cfg =================================================================== --- /dev/null +++ llvm/test/ExecutionEngine/RuntimeDyld/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True