diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 736d9a3e056f1e..a43edd41f5e889 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1011,6 +1011,135 @@ void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section, } } +static void applyUTypeImmRISCV(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 applyITypeImmRISCV(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: { + std::string Err = "Unimplemented reloc type: " + std::to_string(Type); + llvm::report_fatal_error(Err.c_str()); + } + // 32-bit PC-relative function call, macros call, tail (PIC) + // Write first 20 bits of 32 bit value to the auipc instruction + // Last 12 bits to the jalr instruction + case ELF::R_RISCV_CALL: + case ELF::R_RISCV_CALL_PLT: { + uint64_t P = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - P; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + applyITypeImmRISCV(Section.getAddressWithOffset(Offset + 4), PCOffset); + break; + } + // High 20 bits of 32-bit absolute address, %hi(symbol) + case ELF::R_RISCV_HI20: { + uint64_t PCOffset = Value + Addend; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + // Low 12 bits of 32-bit absolute address, %lo(symbol) + case ELF::R_RISCV_LO12_I: { + uint64_t PCOffset = Value + Addend; + applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + // High 20 bits of 32-bit PC-relative reference, %pcrel_hi(symbol) + case ELF::R_RISCV_GOT_HI20: + case ELF::R_RISCV_PCREL_HI20: { + uint64_t P = Section.getLoadAddressWithOffset(Offset); + uint64_t PCOffset = Value + Addend - P; + applyUTypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + break; + } + + // label: + // auipc a0, %pcrel_hi(symbol) // R_RISCV_PCREL_HI20 + // addi a0, a0, %pcrel_lo(label) // R_RISCV_PCREL_LO12_I + // + // The low 12 bits of relative address between pc and symbol. + // The symbol is related to the high part instruction which is marked by + // label. + case ELF::R_RISCV_PCREL_LO12_I: { + for (auto &&PendingReloc : PendingRelocs) { + const RelocationValueRef &MatchingValue = PendingReloc.first; + RelocationEntry &Reloc = PendingReloc.second; + uint64_t HIRelocPC = + getSectionLoadAddress(Reloc.SectionID) + Reloc.Offset; + if (Value + Addend == HIRelocPC) { + uint64_t Symbol = getSectionLoadAddress(MatchingValue.SectionID) + + MatchingValue.Addend; + auto PCOffset = Symbol - HIRelocPC; + applyITypeImmRISCV(Section.getAddressWithOffset(Offset), PCOffset); + return; + } + } + + llvm::report_fatal_error( + "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 = Lo_32(RealOffset); + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + TruncOffset; + break; + } + case ELF::R_RISCV_32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Value + Addend; + break; + } + case ELF::R_RISCV_64: { + auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Value + Addend; + break; + } + case ELF::R_RISCV_ADD16: { + auto Ref = support::ulittle16_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_ADD32: { + auto Ref = support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_ADD64: { + auto Ref = support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)); + Ref = Ref + Value + Addend; + break; + } + case ELF::R_RISCV_SUB16: { + auto Ref = support::ulittle16_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; + } + case ELF::R_RISCV_SUB64: { + auto Ref = support::ulittle64_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. @@ -1076,12 +1205,17 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, case Triple::bpfeb: resolveBPFRelocation(Section, Offset, Value, Type, Addend); break; + case Triple::riscv32: // Fall through. + case Triple::riscv64: + resolveRISCVRelocation(Section, Offset, Value, Type, Addend, SectionID); + break; default: llvm_unreachable("Unsupported CPU type!"); } } -void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const { +void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, + uint64_t Offset) const { return (void *)(Sections[SectionID].getObjAddress() + Offset); } @@ -1870,7 +2004,8 @@ RuntimeDyldELF::processRelocationRef( Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); processSimpleRelocation(SectionID, Offset, RelType, Value); } else if (RelType == ELF::R_X86_64_PC64) { - Value.Addend += support::ulittle64_t::ref(computePlaceholderAddress(SectionID, Offset)); + Value.Addend += support::ulittle64_t::ref( + computePlaceholderAddress(SectionID, Offset)); processSimpleRelocation(SectionID, Offset, RelType, Value); } else if (RelType == ELF::R_X86_64_GOTTPOFF) { processX86_64GOTTPOFFRelocation(SectionID, Offset, Value, Addend); @@ -1884,9 +2019,23 @@ RuntimeDyldELF::processRelocationRef( } else { processSimpleRelocation(SectionID, Offset, RelType, Value); } + } else if (Arch == Triple::riscv32 || Arch == Triple::riscv64) { + // *_LO12 relocation receive information about a symbol from the + // corresponding *_HI20 relocation, so we have to collect this information + // before resolving + if (RelType == ELF::R_RISCV_GOT_HI20 || + RelType == ELF::R_RISCV_PCREL_HI20 || + RelType == ELF::R_RISCV_TPREL_HI20 || + RelType == ELF::R_RISCV_TLS_GD_HI20 || + RelType == ELF::R_RISCV_TLS_GOT_HI20) { + RelocationEntry RE(SectionID, Offset, RelType, Addend); + PendingRelocs.push_back({Value, RE}); + } + processSimpleRelocation(SectionID, Offset, RelType, Value); } else { if (Arch == Triple::x86) { - Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); + Value.Addend += support::ulittle32_t::ref( + computePlaceholderAddress(SectionID, Offset)); } processSimpleRelocation(SectionID, Offset, RelType, Value); } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index b73d2af8c0c490..087338ead639bd 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -60,6 +60,10 @@ class RuntimeDyldELF : public RuntimeDyldImpl { 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 @@ -148,6 +152,9 @@ class RuntimeDyldELF : public RuntimeDyldImpl { // *HI16 relocations will be added for resolving when we find matching // *LO16 part. (Mips specific) + // + // *HI20 relocations will be added for resolving when we find matching + // *LO12 part. (RISC-V specific) SmallVector, 8> PendingRelocs; // When a module is loaded we save the SectionID of the EH frame section